Monday, March 15, 2010

Howto get a list of network interfaces in Linux, part 3

Here we are, this is the ultimate post from these series. Thanks both previous posts, we are now able to get a list of interfaces using any language from shell script to whatever language which can speak ''sockets''.

However, as we could realize earlier, the ioctl-based method does not work exactly the way we want, because it does only report IP enabled devices. So if you want to deal with network interfaces before they start running, you are stuck with the /proc method. There must be another way. Remember that man netdevice we did last week. They mentioned netlink... What are those ?

Netlink sockets are sockets from the AF_NETLINK family. Being sockets, they are used to communicate between two addresses. The fun part is, netlink communications are local. And they usually (in the most simple scenario) link a user process with the kernel, especially the networking stack of the kernel.

Oh great, so we could query the kernel directly, to find out the contents of the global list of interfaces ? Indeed, we will. And since this tutorial is the most tricky of all three, let's have a detailed look at the source code. You can always grab the full source by following the link at the bottom of this post.

First we will open a socket :

int fd;

We already discussed about the socket family, the type should be set to SOCK_RAW (the only one that makes sense here anyway) and the protocol is NETLINK_ROUTE. Why _ROUTE ? There are a few netlink protocols, each dealing with a specific part of the networking stack. NETLINK_XFRM deals with the transform layer used by security and mobility stacks, for example. And the protocol we chose deals with both routes and links.

Now we have to bind that socket. Netlink addresses are based on process ID, so let's do that :

struct sockaddr_nl local;
memset(&local, 0, sizeof(local));
local.nl_family = AF_NETLINK;
local.nl_pid = pid; /* can be obtained using getpid*/
local.nl_groups = 0;

if (bind(fd, (struct sockaddr *) &local, sizeof(local)) < 0)
... error handling ...

If an error occurs it might mean that you are not running the program as super-user or with sufficient rights, or that netlink support is missing in the kernel. And if the bind system call is successful, we can now start sending requests. The request we will be sending, is the one that makes the kernel answer by sending a list of all the interfaces, whatever their state.

typedef struct nl_req_s nl_req_t;

struct nl_req_s {
  struct nlmsghdr hdr;
  struct rtgenmsg gen;
struct sockaddr_nl kernel;
struct msghdr rtnl_msg;
struct iovec io;
nl_req_t req;
memset(&rtnl_msg, 0, sizeof(rtnl_msg));
memset(&kernel, 0, sizeof(kernel));
memset(&req, 0, sizeof(req));
kernel.nl_family = AF_NETLINK; /* fill-in kernel address (destination) */

req.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg));
req.hdr.nlmsg_type = RTM_GETLINK;
req.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
req.hdr.nlmsg_seq = 1;
req.hdr.nlmsg_pid = pid;
req.gen.rtgen_family = AF_PACKET; /*  no preferred AF, we will get *all* interfaces */

io.iov_base = &req;
io.iov_len = req.hdr.nlmsg_len;
rtnl_msg.msg_iov = &io;
rtnl_msg.msg_iovlen = 1;
rtnl_msg.msg_name = &kernel;
rtnl_msg.msg_namelen = sizeof(kernel);

sendmsg(fd, (struct msghdr *) &rtnl_msg, 0);

Okay, so this is the longest piece of code we will be quoting here. First we need to define a structure that can hold our specific message, since netlink can encapsulate so many things, we need to give some structure for this encapsulation. This the the nl_req_t type we just defined.

Then we prepare the destination address for our message. As expected, it is the ''kernel'' address which is specified by all zeroes except the family that is set to AF_NETLINK.

Now we prepare our request. It has a header, and a single message. The header follows the struct nlmsghdr format. In this structure, we will fill information about :
  • the message type : RTM_GETLINK, obviously used to get information about links.
  • the message length. For this, we use the NLMSG_LENGTH macro that makes some alignment calculation and also accounts for the header length. We thus have to pass the size of the payload only, and the result will be the aligned size of the whole netlink message. Our payload is a struct rtgenmsg structure, that is used to specify which address family we are interested in.
  • the message flags : NLM_F_REQUEST because we are sending a request (i.e. requiring an answer) and NLM_F_DUMP.
  • the message sequence number : not very important here because we will only send one message. Note that this number must be monotonically increasing.
  • the message pid : this is our the pid of the sending process, which as we said earlier, is related to the netlink address.
We also fill the rtgen_family field of our payload structure to make sure that we receive information about ALL interfaces, not only IP-related ones. Then we prepare the regular sendmsg stuff using struct msghdr and struct iovec friends.

The message is then complete, and is sent through a sendmsg call. And now, let's get ready for the answer.

int end = 0;
char reply[IFLIST_REPLY_BUFFER]; /* a large buffer */
  while (!end)
      int len;
      struct nlmsghdr *msg_ptr;    /* pointer to current part */
      struct msghdr rtnl_reply;    /* generic msghdr structure */
      struct iovec io_reply;

      memset(&io_reply, 0, sizeof(io_reply));
      memset(&rtnl_reply, 0, sizeof(rtnl_reply));

      io.iov_base = reply;
      io.iov_len = IFLIST_REPLY_BUFFER;
      rtnl_reply.msg_iov = &io;
      rtnl_reply.msg_iovlen = 1;
      rtnl_reply.msg_name = &kernel;
      rtnl_reply.msg_namelen = sizeof(kernel);

      len = recvmsg(fd, &rtnl_reply, 0); /* read lots of data */

This is the first part of the loop that contains most of the initialization logic. It is relying on a end flag that will be updated upon receiving the message that defines an end of answer. Then recvmsg structures are prepared to read a very large message. This netlink message itself can have several message in it's payload, this is why we are going to need a nested loop :

  if (len)
      for (msg_ptr = (struct nlmsghdr *) reply; NLMSG_OK(msg_ptr, len); msg_ptr = NLMSG_NEXT(msg_ptr, len))
        case 3:        /* this is the NLMSG_DONE end msg */
        case 16:    /* this is the RTM_NEWLINK msg */
        default:    /* for education only,
                   should not happen here */
          printf("message type %d, length %d\n", msg_ptr->nlmsg_type, msg_ptr->nlmsg_len);

Here we use a few of those NLMSG macros, to walk the big netlink message. Basically, NLMSG_OK checks that the message specified by the parameter pointer is indeed a valid netlink message, while NLMSG_NEXT steps over a single iteration, moving from the parameter pointer current message to the next message in the netlink payload, while the global length is specified to avoid buffer overrun. Upon receiving NLMSG_DONE message, we just update our end of loop condition. And we use a separated function to print out new link information. Here it is :

rtnl_print_link(struct nlmsghdr *h)
  struct ifinfomsg *iface;
  struct rtattr *attribute;
  int len;

  iface = NLMSG_DATA(h);
  len = h->nlmsg_len - NLMSG_LENGTH(sizeof(*iface));

  for (attribute = IFLA_RTA(iface); RTA_OK(attribute, len); attribute = RTA_NEXT(attribute, len))
        case IFLA_IFNAME:
          printf("Interface %d : %s\n", iface->ifi_index, (char *) RTA_DATA(attribute));

Very simple function made of mostly a big loop. Here we can find some new macros that look a lot like the NLMSG ones. They have an equivalent behavior but are handling different data. NLMSG_ macros are handling the netlink message and allows to parse all parts of a multi-part query or request. Then, each part itself is made of several attributes (think of route information here, routes have lots of attributes, and so do links). So RTA_ stands for route attribute, and the effect of the RTA macros is identical to NLMSG ones. This allows us to loop over ALL attributes of a link.

Also, in order to catch the first of those RTAs, we need to know where they start. This depends on the kind of message we received, but as far as this function is concerned, the message type is known to be RTM_NEWLINK. So IFLA_RTA allows us to get a pointer to the first attribute in the RTM_NEWLINK message.

For the sake of this exemple, we will only consider the interface name, but there is much more information (MTU, hardware address, link type, flags, state, etc...). You can check out for more information, like the list of possible attributes.

And now, let's run our example :

Interface 1 : lo
Interface 2 : eth1
Interface 3 : wlan1
Interface 4 : pan0

Where we can see that they are all returned, including the down ones. Victory ! By the way, the number we are printing here is the interface index, that is very useful for subsequent actions, you'd better store it next to the interface name.

I hope this was an interesting (long) read. Again, feel free to use this code provided you give proper credits.

PS: for the lazy people who want to try it right away, here is a link to the full source.


Unknown said...

nl80211 is a cool interface. You might also consider reading /proc/net/dev as well.

Maverick said...

Hey Jean...I am writing module to access information of TAP interface,the information would be bridge related ,like STP port state and others.
I would like to know whether bridge related information can I get using RTM_GETLINK

werewolf said...

if we have eth0 and eth0:1 will there name have seperate index

Anonymous said...

Thank you Jean!

Vicky said...

How will we display only a particular interface by some matching criteria using NLM_F_MATCH?

otr said...

Work from home theory is fast gaining popularity because of the freedom and flexibility that comes with it. Since one is not bound by fixed working hours, they can schedule their work at the time when they feel most productive and convenient to them. Women & Men benefit a lot from this concept of work since they can balance their home and work perfectly. People mostly find that in this situation, their productivity is higher and stress levels lower. Those who like isolation and a tranquil work environment also tend to prefer this way of working. Today, with the kind of communication networks available, millions of people worldwide are considering this option.

Women & Men who want to be independent but cannot afford to leave their responsibilities at home aside will benefit a lot from this concept of work. It makes it easier to maintain a healthy balance between home and work. The family doesn't get neglected and you can get your work done too. You can thus effectively juggle home responsibilities with your career. Working from home is definitely a viable option but it also needs a lot of hard work and discipline. You have to make a time schedule for yourself and stick to it. There will be a time frame of course for any job you take up and you have to fulfill that project within that time frame.

There are many things that can be done working from home. A few of them is listed below that will give you a general idea about the benefits of this concept.

This is the most common and highly preferred job that Women & Men like doing. Since in today's competitive world both the parents have to work they need a secure place to leave behind their children who will take care of them and parents can also relax without being worried all the time. In this job you don't require any degree or qualifications. You only have to know how to take care of children. Parents are happy to pay handsome salary and you can also earn a lot without putting too much of an effort.

For those who have a garden or an open space at your disposal and are also interested in gardening can go for this method of earning money. If given proper time and efforts nursery business can flourish very well and you will earn handsomely. But just as all jobs establishing it will be a bit difficult but the end results are outstanding.

Freelance can be in different wings. Either you can be a freelance reporter or a freelance photographer. You can also do designing or be in the advertising field doing project on your own. Being independent and working independently will depend on your field of work and the availability of its worth in the market. If you like doing jewellery designing you can do that at home totally independently. You can also work on freelancing as a marketing executive working from home. Wanna know more, email us on and we will send you information on how you can actually work as a marketing freelancer.

Internet related work
This is a very vast field and here sky is the limit. All you need is a computer and Internet facility. Whatever field you are into work at home is perfect match in the software field. You can match your time according to your convenience and complete whatever projects you get. To learn more about how to work from home, contact us today on workfromhome.otr214428@gmail.comand our team will get you started on some excellent work from home projects.

Diet food
Since now a days Women & Men are more conscious of the food that they eat hence they prefer to have homemade low cal food and if you can start supplying low cal food to various offices then it will be a very good source of income and not too much of efforts. You can hire a few ladies who will help you out and this can be a good business.

Thus think over this concept and go ahead.

Unknown said...

Thx for good post.

Link to full project is dead.

Unknown said...

Thanks for your post. I have question, is there any sample program for collecting the survey data,?

Unknown said...

Thanks for the nice post.
Unfortunately, the link to the sources is down, could you update it?