Starting ethernet communication: select_device

Firstly, have a look at the IP stack @ http://en.wikipedia.org/wiki/Internet_protocol_suite . It explains stuff. Though its wikipedia, its quite detailed and technical, which is brilliant. I am really bothered abt the figure, btw, that 5 layer table.

 

Anyways, lets explore libnet. We see a doc folder. Go, and see the HTML documents, serial order ofcourse. You’d understand the first 3-4 pages. If you don’t, fuck off- either u aint concentrating, or you don’t know enough. If its the first, good, thats what happened to me the first time. But if its 2nd, you need to wait for another 1/2 year to get and read material pre-requisite to this blog.

 

Now, in your opera/firefox , open 2 tabs, 1 having 5.html and other 6.html . These are by far the 2 most important documents you’d need to be open.

 

Since we’re dissecting the source, we wouldnt bother much with the memory management part of libnet, atleast as yet. We are more interested in the communication with the modem/router/card, and how to form and send packet headers (along with payload if any). I DONT know the entire process as yet, so I might make some mistakes here, and rectify/negate them later. Don’t scream @ me, I aint accountable to you, its my blog!

 

Anyways, I assume that basic IP headers are easier to construct. So, lets start off with link layer instead, which is definately much more complex, but is found “NOWHERE” (no book, very very few source codes, no articles, hardly any papers, nothing abt link layer programming)

 

So, we see that the basic way to start a link layer communication is by libnet_open_link_interface. Read 5.html. It takes 2 arguments. The first is important, its the device. The second is merely an error buffer for error message. From the practical point of view, we must first find out which device is to be used. We must use a non-loopback device, which is up (ie, working). To do this, lets use the libnet_select_device() function.

 

libnet_select_device -
It takes the form: int libnet_select_device(struct sockaddr_in *sin, u_char **device, u_char *ebuf); . Dont be perplexed. Breaking it down-
sockaddr_in is that SOCKADDR structure for the Internet suite. Its basically sockaddr but casted better, in more human readable form.
**device : No sweat. Make a blank string. Pass the address of the string (ye, address of pointer of first character of string). I realise this is pretty retarded however, since you could modify the string without the pointer address.
*ebuf: Just an empty string, which could have an error message if there is some error.
On failure, the function returns -1. Else, contains true (1).

 

For example

 

.....
char *device=NULL,*buf=NULL;
struct sockaddr_in sin; //lame
if(libnet_select_device(&sin,&device,buf)==-1){ printf("Your interface is down or sumthing: %s",buf); exit(1); }
.... //Use device for the rest of the time.

 

That was a for example. You could use the pcap interface (remember, libnet is useful for sending packets, but usually with libpcat for sniffing the net, libnet’s power increases manifolds), Cause thats whats done in dniff (which is a open source sniffer)

 

(sideline note: Just running thru connecting with devices routines, ahem, very complex guys… all distinct and stuff)

 

The libnet_select_device is present in /src/libnet_if_addr.c file. Opening that, here’s libnet_select_device function-
int
libnet_select_device(struct sockaddr_in *sin, u_char **device, u_char *errbuf)
{
int c, i;
char err_buf[BUFSIZ];
struct libnet_ifaddr_list *address_list;
#if (__solaris__)
/*
* XXX - this is temporary and needs to be better documented.
*/
*device = "le0";
return (1);
#else
/*
* Number of interfaces.
*/
c = libnet_ifaddrlist(&address_list, err_buf);
if (c < 0)
{
sprintf(errbuf, "ifaddrlist : %s\n", err_buf);
return (-1);
}
else if (c == 0)
{
sprintf(errbuf, "No network interfaces found.\n");
return (-1);
}
if (*device)
{
for (i = c; i; --i, ++address_list)
{
if (!(strncmp(*device, address_list->device, strlen(address_list->device))))
{
break;
}
}
if (i <= 0)
{
sprintf(errbuf, "Can't find interface %s\n", *device);
return (-1);
}
}
sin->sin_family = AF_INET;
sin->sin_addr.s_addr = address_list->addr;
/*
* Do we need to assign a name to device?
*/
if (!*device)
{
if (c > 1)
{
#if (__DEBUG)
fprintf(stdout,
"Multiple interfaces found, using %s @ %s.\n",
host_lookup(sin->sin_addr.s_addr, 0),
address_list->device);
#endif
}
*device = address_list->device;
}
return (1);
}
#endif /* __solaris__ */

 

We see that script has support for solaris: A system we don’t bother exploring. But looks like the default active modem device is set by the handle le0 automatically. lol, solaris rox for this.
But linux aint so lucky. First, it checks through ifaddrlist for some stuff…. Yeah, I’m looking at that function now… check it out, its right above select_device (I’d describe it in my next post perhaps. This 1 is for select_device)

 

Deviation: Since this is taking longer then anticipated, here are links which I used to find out how stuff is done:
http://docs.sun.com/app/docs/doc/802-1930-07/6i5u9741f?a=view – Cool link.
http://ecos.sourceware.org/docs-latest/ref/openbsd-manpages-netintro.html – BSD reference for ifreq and ioctl
http://www.delorie.com/gnu/docs/glibc/libc_305.html – If sa_len is not defined (if defined, then see first link)

 

And done (phew), after abt 1/2-1 hour. I’ll admit it, I never used ioctl ever in my life before, and finding out stuff about it is hard.

 

Anyways, back to the code. The libnet_ifaddrlist() takes a regular double pointer to libnet_ifaddr_list and in that pointer, returns a list of active interfaces (non-loopback). Each entry of the array returned contains a device name, and the mac address of the interface. It returns the number of interfaces.

 

So, c is returned the number of interfaces (back in libnet_select_device btw). As you can see, it select device does some bogus checks at first. Then, it goes and checks if a particular device is working or not. This is simple to check really. Just go through the devices returned by libnet_ifaddrlist , and compare if any of the devices in that list match the device passed. This is, ofcourse, followed, only if device argument is not null (we normally use null right, to GET the device. But this function can also check the validity of a device).

 

Then it merely copies the device(s), if multiple, then the first device in the array. This device is simply copied to the passed **device argument, and a nice “true” is returned.

 

Sorry: Sorry to disappoint. I thought the function will be more involved, but turns out that the libnet_ifaddrlist is the beast, not select_device. I realised that WHEN I was writing this post.

 

Use: Not much, I’ll give you that. The function itself is quite easy to understand if you know about libnet structures and stuff in general, and I’m happy it turned out to be the first I discussed, cause it was easy. However, I can’t help to say, it was more like a wrapper function+”little” functionality+error reporting . But this is a very useful function in general, for getting the most convenient interface. However, we havent discussed enough for a full fledged program to exploit this function.

 

Whats next: Duh, next post, which will be prob after much much more extensive research (lol, most of it, done today, but I prefer real EXTENSIVE.) is about lib_ifaddrlist . Wish me luck about finding about Ifflags in linux.


About this entry