How to check Ethernet in Linux? - c

I need the test case for Ethernet in Linux using C code to check eth0. If eth0 is down, we enable the net then check if up and the test is passed.

To check if the link is up, try something like this. It works without root privileges.
#include <stdio.h> // printf
#include <string.h> // strncpy
//#include <sys/socket.h> // AF_INET
#include <sys/ioctl.h> // SIOCGIFFLAGS
#include <errno.h> // errno
#include <netinet/in.h> // IPPROTO_IP
#include <net/if.h> // IFF_*, ifreq
#define ERROR(fmt, ...) do { printf(fmt, __VA_ARGS__); return -1; } while(0)
int CheckLink(char *ifname) {
int state = -1;
int socId = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
if (socId < 0) ERROR("Socket failed. Errno = %d\n", errno);
struct ifreq if_req;
(void) strncpy(if_req.ifr_name, ifname, sizeof(if_req.ifr_name));
int rv = ioctl(socId, SIOCGIFFLAGS, &if_req);
close(socId);
if ( rv == -1) ERROR("Ioctl failed. Errno = %d\n", errno);
return (if_req.ifr_flags & IFF_UP) && (if_req.ifr_flags & IFF_RUNNING);
}
int main() {
printf("%d\n", CheckLink("eth0"));
}
If IFF_UP is set, it means interface is up (see ifup). If IFF_RUNNING is set then interface is plugged.
I also tried using the ethtool ioctl call, but it failed when the gid was not root. But just for the log:
...
#include <asm/types.h> // __u32
#include <linux/ethtool.h> // ETHTOOL_GLINK
#include <linux/sockios.h> // SIOCETHTOOL
...
int CheckLink(char *ifname) {
...
struct ifreq if_req;
(void) strncpy( if_req.ifr_name, ifname, sizeof(if_req.ifr_name) );
struct ethtool_value edata;
edata.cmd = ETHTOOL_GLINK;
if_req.ifr_data = (char*) &edata;
int rv = ioctl(socId, SIOCETHTOOL, &if_req);
...
return !!edata.data;
}

The network interfaces can be seen in sysfs: /sys/class/net/eth[x]. There you can check the link, interface status, and more.

You may want to take advantage of libudev to get around in /sys:
http://www.signal11.us/oss/udev/

I simply check if an Ip address is assigned to the network card.
You can use something like this to check if lan is up in the given network card (say eth0) :
/sbin/ifconfig eth0| grep 'inet addr:' | wc -l
This should simply return 0 or 1 based on whether or not an ip address is assigned to the nic.
Also you may use Yann Ramin's method to list out all the nic's & perform the check.
I missed out noticing you are looking for a c code. Maybe adding a tag would be good.
Either ways, I think you can look at the same file (ifconfig) manually in c by reading it for an ip.

As this question is somewhat important, I'll add another answer despite its extreme age. You can read the contents of /sys/class/net/eth0/operstate which will simply contain the string "up\n" or "down\n".

Related

How to check if the IP address that a socket is bound to is still one of the valid machine's addresses?

Once I call socket(); bind() (with a specific IP address, not INADDR_ANY); listen(), there seems to be no way of determining if the IP address is still a valid address of one of the system's interfaces.
What I looked into using:
Checking error with getsockopt(SO_ERROR);
Using epoll()-ing on some EPOLLERR, EPOLL{,RD}HUP events;
Hoping that accept() would return an error if the IP address is deleted when process is blocked on this syscall;
Non of those above seem to detect the IP address vanishing and/or change of interface state at all.
Calling bind() in some timer callback to periodically check if the IP address may be bound, but this requires another socket has to be created it is not feasible.
I did not test these:
Setting SO_BINDTODEVICE in the hope that this will change behavior of the facilities from the first triple in case interface goes down/IP address is removed.
Calling some ioctl() like SIOCSPGRP or FIOASYNC since they promise to signal process about asynchronous events that hopefully include disappearance of an IP address.
Using netlink to get routing table events, but this is very Linux-specific.
I'm hopping for a more portable way.
What I needing is some event similar to RDMA_CM_EVENT_DEVICE_REMOVAL, but with AF_INET sockets that would notify me when there is no bound interface with that IP address. Even this may be impossible to fulfill, because even bind() completes without error if the interface is down.
You do not need to close a socket when the link goes down with BSD sockets.
This other questions shows how to listen for network routing changes mentioned by Remy.
A simpler way may be to check if the IP is currently bound before using the socket. This is a way to verify that 127.0.0.1 is still valid:
% cat checksocket.c && cc -o checksocket checksocket.c ; ./checksocket
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <ifaddrs.h>
#include <netdb.h>
#include <net/if.h>
int main (void)
{
struct ifaddrs *ifa, *i;
char host[NI_MAXHOST];
int ret = getifaddrs(&ifa);
if (ret) {
perror("getifaddrs:");
exit(EXIT_FAILURE);
}
for (i = ifa; i != NULL; i = i->ifa_next) {
ret = getnameinfo(i->ifa_addr, sizeof(*(i->ifa_addr)),
host, sizeof(host), NULL, 0, NI_NUMERICHOST);
char find[] = "127.0.0.1";
int len = strlen(host);
if (!ret && len && !strncmp(host, find, len)) {
printf("Still valid: %s %s\n", i->ifa_name, ret ? "" : host);
}
}
freeifaddrs(ifa);
return 0;
}
Still valid: lo0 127.0.0.1

How to get current running ethernet speed from LabWindows\CVI C code or CMD commands

I am developing Test Equipment which has couple of Ethernet ports. As part of the testing i want to check the current speed of the ethernet ports (10/100/1000) when a tested unit is connected.
How can i get this information? is there a C library or CMD command which i can use that can supply this information?
C# is probably quicker to get up and running than API access with c/c++.
Try using the System.Net.NetworkInformation classes. In particular, System.Net.NetworkInformation.IPv4InterfaceStatistics ought to have some information along the lines of what you're looking for.
Specifically, you can check the bytesReceived property, wait a given interval, and then check the bytesReceived property again to get an idea of how many bytes/second your connection is processing. To get a good number, though, you should try to download a large block of information from a given source, and check then; that way you should be 'maxing' the connection when you do the test, which should give more helpful numbers.
You need a linux running machine for the code to work
You need to use the SIOCETHTOOL ioctl() call in Linux.
#include <stdio.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <linux/sockios.h>
#include <linux/if.h>
#include <linux/ethtool.h>
#include <string.h>
#include <stdlib.h>
int main (int argc, char **argv)
{
int sock;
struct ifreq ifr;
struct ethtool_cmd edata;
int rc;
sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
if (sock < 0) {
perror("socket");
exit(1);
}
strncpy(ifr.ifr_name, "eth0", sizeof(ifr.ifr_name));
ifr.ifr_data = &edata;
edata.cmd = ETHTOOL_GSET;
rc = ioctl(sock, SIOCETHTOOL, &ifr);
if (rc < 0) {
perror("ioctl");
exit(1);
}
switch (ethtool_cmd_speed(&edata)) {
case SPEED_10: printf("10Mbps\n"); break;
case SPEED_100: printf("100Mbps\n"); break;
case SPEED_1000: printf("1Gbps\n"); break;
default: printf("Speed returned is %d\n", edata.speed);
}
return (0);
}
I'm not sure about the Windows .May be you can refer here: Microsoft Developer Network
use wmic command like this
wmic PATH Win32_NetworkAdapter WHERE "PhysicalAdapter = TRUE AND NetEnabled = TRUE" GET Name, Speed
Win32_NetworkAdapter classof WMI

Why does bind (socket binding) method generate a file in the current directory?

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
int main()
{
int sock;
struct sockaddr sock_name = {AF_UNIX, "Fred"};
socklen_t len=sizeof(struct sockaddr)+5;
if( (sock=socket(AF_UNIX,SOCK_STREAM,0)) ==-1)
{
printf("error creating socket");
return -1;
}
if( bind(sock,&sock_name,len) != 0 )
{
printf("socket bind error");
return -1;
}
close(sock);
return 0;
}
After the first run, this program keeps reporting binding error. I tried to change the name of the sockaddr. It works again. But after changing it back to "Fred" (in this case), the error continues. Is something being stored in memory I didn't clear? Why does this happen and how could I fix it?
I guess I have found the problem. After the first run, I find a file named "Fred" in the current directory. I removed the file and my program worked again. Why does bind method generate a file in the current directory?
When used with Unix domain sockets, bind(2) will create a special file at the specified path. This file identifies the socket in much the same way a host and port identify a TCP or UDP socket. Just like you can't call bind twice to associate two different sockets with a given host and port*, you can't associate more than one Unix socket
But why doesn't the file disappear when you call close(2)? After all, closing a TCP socket makes the host and port it was bound to available for other sockets.**
That's a good question, and the short answer is, it just doesn't.
So it's customary (at least in example code) to call unlink(2) prior to binding. The Unix domain socket section of Beej's IPC guide has a nice example of this.
*With versions of the Linux kernel >= 3.9, this isn't exactly true.
**After TIME_WAIT or immediately if you use the SO_REUSEADDR socket option.
EDIT
You said this is your teacher's code, but I suggest that you replace your printf calls with perror:
if( bind(sock,&sock_name,len) != 0 )
{
perror("socket bind error");
return -1;
}
...which will print out a human-readable representation of the real problem encountered by bind(2):
$ ./your-example-executable
$ ./your-example-executable
socket bind error: Address already in use
Programming doesn't have to be so inscrutable!
When you successfully open a socket, it stays open until it is closed (even if your program terminates).
It appears that the question code is not closing the socket in the event of an (such as the failure of bind()).
Two processes cannot generally open the same socket.
Each time the code is executed, it is a new process, attempting to open the same socket.
The code needs a better scheme to handle errors.
This is how I would do it:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#define MY_FALSE (0)
#define MY_TRUE (-1)
int main()
{
int rCode=0;
int sock = (-1);
char *socketFile = "Fred");
struct sockaddr sock_name = {AF_UNIX, socketFile};
socklen_t len=sizeof(struct sockaddr)+5;
int bound = MY_FALSE;
if((sock=socket(AF_UNIX,SOCK_STREAM,0)) ==-1)
{
printf("error creating socket");
rCode=(-1);
goto CLEANUP;
}
if( bind(sock,&sock_name,len) != 0 )
{
printf("socket bind error");
rCode=(-1);
goto CLEANUP;
}
bound=MY_TRUE;
This single 'cleanup' area can be used to free allocated memory, close sockets & files, etc.
CLEANUP:
if((-1) != sock)
close(sock);
if(bound)
unlink(socketFile);
return 0;
}

Similar to getifaddrs on old glibc version

There is very useful funcion call getifaddrs which retrieves all machin network addresses. The problem is that I'm using old glibc version which doesn't have this function. Is there any replacement for it? I was looking and found getipnodebyname but it is unuseful when address isn't mapped in /etc/hosts file.
To add to the previous answer, here is an example for the SIOCGIFCONF-approach. You have to do something like this:
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#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 fd;
int get_iface_list(struct ifconf *ifconf)
{
int rval;
if((rval = ioctl(fd, SIOCGIFCONF , (char*) ifconf )) < 0 )
perror("ioctl(SIOGIFCONF)");
return rval;
}
int main()
{
static struct ifreq ifreqs[100];
static struct ifconf ifc;
char *ptr;
fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fd < 0)
return 1;
ifc.ifc_buf = (char*) (ifreqs);
ifc.ifc_len = sizeof(ifreqs);
if(get_iface_list(&ifc) < 0) return -1;
/* Go through the list of interfaces */
for (ptr = ifc.ifc_buf; ptr < ifc.ifc_buf + ifc.ifc_len;)
{
struct ifreq *ifr = (struct ifreq*)ptr;
int len = (sizeof(struct sockaddr) > ifr->ifr_addr.sa_len) ?
sizeof(struct sockaddr) : ifr->ifr_addr.sa_len;
ptr += sizeof(ifr->ifr_name) + len;
/* Do what you need with the ifr-structure.
* ifr->ifr_addr contains either sockaddr_dl,
* sockaddr_in or sockaddr_in6 depending on
* what addresses and L2 protocols the interface
* has associated in it.
*/
}
close(fd);
return 0;
}
There are some gotchas, of course. According to Unix Network Programming chapter 17.6 ioctl(fd, SIOCGIFCONF, array) may not return an error on some platforms if the array pointed in the argument is too small. The data will then be concatenated. Only way to work around this is to call ioctl() in a loop until you get same result length twice while increasing the size of the array. Of course, since this is 2012, I'm not sure how relevant this is anymore.
Size of ifreqs array is purely a guess in this case. Keep in mind though that the array will contain one struct ifreq for every L2 and L3 address associated with a interface. For example, assuming you have also IPv6 addresses, for lo-interface you'd get three entries: ethernet, IPv4 and IPv6. Therefore reserve enough space or apply the kludge.
To get broadcast addresses and other additional information, you will need to additional ioctl() calls in the loop. All possible options depends on what your OS provides, of course.
For more information I'd recommend reading Unix Network Programming by W. Richard Stevens. It is the most comprehesive book about this subject.
The traditional way to do the equivalent was with the SIOCGIFCONF operation to ioctl. Any socket can be used for the operation. It's not as easy as a single function call though.

Raw Sockets on BSD Operating Systems

I've been writing some sockets code in C. I need modify packet headers and control how they're sent out, so I took the raw sockets approach. However, the code I wrote will not compile on BSD systems (Mac OS X/Darwin, FreeBSD, etc.)
I've done a bunch of research on this and have found that BSD systems can't handle raw sockets the way Linux (or even Windows) does. From what I've read, it seems I need to use bpf (berkley packet filter), but I can't figure out how bpf works or how I would go about using it with raw sockets.
If someone could shed some light on this one, I'd be very excited :D
P.S. I'll even be happy with some source code showing how raw sockets are handled in a BSD environment. It doesn't have to be a guide or explanation. I just want to see how it works.
Using raw sockets isn't hard but it's not entirely portable. For instance, both in BSD and in Linux you can send whatever you want, but in BSD you can't receive anything that has a handler (like TCP and UDP).
Here is an example program that sends a SYN.
#include <sys/socket.h>
#include <sys/types.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <err.h>
#include <stdio.h>
#include <string.h>
#include <sysexits.h>
int
main(int argc, char *argv[])
{
int s, rc;
struct protoent *p;
struct sockaddr_in sin;
struct tcphdr tcp;
if (argc != 2)
errx(EX_USAGE, "%s addr", argv[0]);
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = 0;
/* Parse command line address. */
if (inet_pton(AF_INET, argv[1], &sin.sin_addr) <= 0)
err(EX_USAGE, "Parse address");
/* Look up tcp although it's 6. */
p = getprotobyname("tcp");
if (p == NULL)
err(EX_UNAVAILABLE, "getprotobyname");
/* Make a new shiny (Firefly) socket. */
s = socket(AF_INET, SOCK_RAW, p->p_proto);
if (s < 0)
err(EX_OSERR, "socket");
memset(&tcp, 0, sizeof(tcp));
/* Fill in some random stuff. */
tcp.th_sport = htons(4567);
tcp.th_dport = htons(80);
tcp.th_seq = 4; /* Chosen by fair dice roll. */
tcp.th_ack = 0;
tcp.th_off = 5;
tcp.th_flags = TH_SYN;
tcp.th_win = htonl(65535);
rc = sendto(s, &tcp, sizeof(tcp), 0, (struct sockaddr *)&sin,
sizeof(sin));
printf("Wrote %d bytes\n", rc);
return 0;
}
Of course, more BSD-specific solutions are available. For instance you could use divert(4) to intercept packets as they traverse your system and alter them.

Resources