I have a basic server-client program that I'm writing in C and I am stuck with an issue regarding strings and concatenation.
Basically I have some strings (in the example below just 2) that I have to put into a buffer which size is determined by:
total # of registered people * 33
Both the strings in the example have a length which is much less than the length of the buffer. I want to obtain something like this after the concatenation:
[0] [32]
people_list=Mark Amy\0;
where Mark(which is inserted secondly) is right at the start of the buffer (people_list) and Amy is 32 characters away from the start of Mark (I hope I've made myself clear).
This is because the client code was given to me and I cannot modify it. The client code takes the buffer and reads the first element, then jumps of 32 chars and reads again.
The output I get from the printf of the client is this:
connected to server
Registered people:
Mark
while I'd like this:
connected to server
Registered people:
Mark
Amy
The communication is implemented through sockets, which I have already checked, but if you wish to suggest some changes I would appreciate that.
Server code:
#include <stdio.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <errno.h>
#define LENGTH 32
struct person {
char name[LENGTH+1];
struct person *next;
struct person *prev;
};
struct person *p_head = NULL;
void addPerson(char* name_p){
struct person *new = (struct person*) malloc(sizeof(struct person));
strcpy(new->name, name_p);
new->name[LENGTH]='\0';
new->next=p_head;
new->prev=NULL;
p_head=new;
}
int main(){
int fd_ser;
int fd_c;
int N=100;
char buf[N];
int times=0;
char* path="tmp/sock";
struct sockaddr_un sa;
unlink(path);
sa.sun_family=AF_UNIX;
strncpy(sa.sun_path,(char*) path, sizeof(sa.sun_path));
if((fd_ser=socket(AF_UNIX,SOCK_STREAM,0))<0){ //socket
perror((const char*) (size_t) errno);
exit(EXIT_FAILURE);
}
if ( bind(fd_ser,(struct sockaddr *)&sa, sizeof(sa))<0){
perror("bind\n");
}
listen(fd_ser,10); //listen
struct sockaddr_un addr;
int addr_size= sizeof(struct sockaddr_un);
fd_c=0;
while( (fd_c=accept(fd_ser,(struct sockaddr*) &addr, (socklen_t*)&addr_size))<0){
printf("waiting for connections...\n");
sleep(2);
}
//initialize list of people
char* Amy="Amy";
char* Mark="Mark";
addPerson(Amy);
addPerson(Mark);
//now concat the name strings in a buffer to be sent to the client
char* people_list;
unsigned int list_len;
int value;
struct person* ptr=(struct person*) malloc(sizeof(struct person));
ptr=p_head;
int offset=0;
int i=0;
while(ptr!=NULL){
i++;
people_list=realloc(people_list,i*LENGTH); //every single name has to be LENGTH characters
strcpy(&people_list[offset],ptr->name);
ptr=ptr->next;
offset=offset+LENGTH;
}
people_list[i*LENGTH]='\0';
list_len=(i*LENGTH)+1;
value=write(fd_c, &(list_len), sizeof(unsigned int));
if(value==-1){
perror("write length");
return -1;
}
int toWrite=list_len;
char *toRead=people_list;
while(toWrite>0){
value=write(fd_c, toRead, toWrite);
if(value==-1){
perror("write data");
return -1;
}
toWrite=toWrite-value;
toRead=toRead+value;
if(toRead<=people_list + list_len) break;
}
close(fd_c);
close(fd_ser);
return 0;
}
Client code:
#include <stdio.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <assert.h>
#include <errno.h>
#define MAX_LENGTH 2048
#define LENGTH 32
int main(){
int fd_cli;
char* path="tmp/sock";
struct sockaddr_un sa;
sa.sun_family=AF_UNIX;
strncpy(sa.sun_path,(char*) path, sizeof(sa.sun_path));
if( (fd_cli = socket(AF_UNIX, SOCK_STREAM, 0))==-1){
perror((const char*) (size_t) errno);
return -1;
}
while( (connect(fd_cli,(struct sockaddr*)&sa, sizeof(struct sockaddr_un))) == -1 ) {
if ( errno == ENOENT ) { sleep(1); }
else perror("connect:");
errno=0;
sleep(1);
}
printf("connected to server\n");
int value;
unsigned int len_data;
value=read(fd_cli,&(len_data),sizeof(unsigned int));
if(value==-1){
perror("read length");
return -1;
}
char* buffer=malloc(len_data*sizeof(char));
int toRead=len_data;
char *toWrite=buffer;
while(toRead>0){
value=read(fd_cli, toWrite, toRead);
if(value==-1){
perror("read buffer");
return -1;
}
toRead=toRead-value;
toWrite=toWrite+value;
if(toWrite<=buffer + len_data) break;
}
int people_n = len_data / (LENGTH+1);
assert(people_n > 0); //proceeds only if there is at least one person registered
printf("Registered people:\n");
for(int i=0,p=0;i<people_n; ++i, p+=(LENGTH+1)) {
printf(" %s\n", &buffer[p]);
}
close(fd_cli);
return 0;
}
I really hope I've explained the problem clearly! Thank you for your help!
It's printing only the first user (Mark) because of this line:
int people_n = len_data / (LENGTH+1);
In this example, len_data = 65, LENGTH = 32. So when you are adding 1 to LENGTH, it will return 1 (65/33 = 1.96 => you get 1). Then it only prints the first user.
Consider using Valgrind. It will help you checking the use of the memory.
Related
This code scans for newly created files within a directory, however where "%s" should contain the name of the new file(s) this does not occur.
I can imagine there are unnecessary pieces of code written here, however being quite unfamiliar with C I'm simply happy it compiles at this point (and actually recognizes new files) !
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <sys/inotify.h>
int main (int argc, char *argv[])
{
char target[FILENAME_MAX];
int result;
int fd;
int wd; /* watch descriptor */
const int event_size = sizeof(struct inotify_event);
const int buf_len = 1024 * (event_size + FILENAME_MAX);
fd = inotify_init();
if (fd < 0) {
perror("inotify_init");
}
wd = inotify_add_watch(fd, "/home/joe/Documents", IN_CREATE);
while (1) {
char buff[buf_len];
int no_of_events, count = 0;
no_of_events = read (fd, buff, buf_len);
while (count < no_of_events) {
struct inotify_event *event = (struct inotify_event *)&buff[count];
if (event->len) {
if (event->mask & IN_CREATE)
if(!(event->mask & IN_ISDIR)) {
printf("The file %s has been created\n", target);
fflush(stdout);
}
}
count += event_size + event->len;
}
}
return 0;
}
You're printing out target when you get an event, however target is never modified.
The name of the created file is stored in event->name. That's what you want to print.
printf("The file %s has been created\n", event->name);
I have a simple struct as follows:
typedef struct {
char *raw_headers;
char headers[128][512][512];
} HTTPrequest;
Now in the same file I have a function as follows:
void init_request(char *raw_headers) {
HTTPrequest request;
request.raw_headers = raw_headers;
}
This results in a Segmentation Fault when running the output binary.
I compile the file, as
$ gcc Server.c -o Builds/debug
And, I run the executable as,
$ ./Builds/debug
This is my original file as requested:
Parser.h
typedef struct {
char *raw_headers;
char headers[128][512][512];
} HTTPrequest;
void parser_init(char *raw_headers) {
char *token, *key_value = NULL;
token = strtok(raw_headers, "\r\n");
int line_counter = 1
HTTPrequest request;
request.raw_headers = raw_headers;
while (token) {
char *line = token;
if(line_counter != 1) {
}
token = strtok(NULL, "\r\n");
line_counter++;
}
}
Server.h
int socket_create() {
return socket(AF_INET, SOCK_STREAM, 0);
}
void infinite_loop(int socketFD) {
char buffer[1024];
memset(buffer, 0, sizeof(buffer));
printf("Starting infinite loop, don't worry, everything would be okay!\n");
do {
int connectionFD = accept(socketFD, (struct sockaddr*) NULL, NULL);
/*Accept is a blocking call! The following code wont execute until, accept() returns.*/
strcpy(buffer, "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\nHello!");
write(connectionFD, buffer, sizeof(buffer));
char request[2048];
memset(&request, 0, sizeof(request));
read(connectionFD, &request, sizeof(request));
printf("Request received!\n");
// Init the parser.
parser_init(request);
close(connectionFD);
} while (true);
}
Server.c
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <stdbool.h>
#include "Parser.h"
#include "Server.h"
void main() {
struct sockaddr_in listeningAddr;
int socketFD = socket_create();
memset(&listeningAddr, 0, sizeof(listeningAddr));
listeningAddr.sin_family = AF_INET;
listeningAddr.sin_addr.s_addr = htonl(INADDR_ANY);
listeningAddr.sin_port = htons(8070);
bind(socketFD, (struct sockaddr*) &listeningAddr, sizeof(listeningAddr));
if(listen(socketFD, 5) == -1) {
printf("Woah there! I couldn't startup the server!");
}
infinite_loop(socketFD);
}
Also, the error message: Segmentation fault (core dumped)
The headers member (32MiB) makes your struct too big to fit on most default system-provided stacks (8MiB on Linux).
Make it smaller, and trivial MCVEs such as:
typedef struct {
char *raw_headers;
char headers/*[128]*/[512][512]; }
HTTPrequest;
void init_request(char *raw_headers) {
HTTPrequest request;
request.raw_headers = raw_headers;
}
int main()
{
init_request("hello, world");
}
will work, although, initializing an on-stack struct only to have it discarded by the function return is not very meaningful
(Initializer functions will usually take a pointer to the struct they're initializing and initialize the object through that pointer.)
Although your HTTPrequest is simple, it is over 32MB in size. You most probably encounter a stack overflow...
That's a typical case of Stack overflow!
The reason is that your struct HTTPrequest is too big, more than 32 MB. The 3D array has a size of 128 * 512 * 512 = 33554432 bytes, since it's of type char.
In any case, 3D arrays are barely used, and only in special cases. Reconsider your design and try to make that array a 2D instead of a 3D.
i'm writing a server/client c program based on AX.25 protocol.
The server creating the socket, binding Successfully and listening for coming connections.
the client running in a different thread but fails on connect with " No route to host"
Server code
#include <sys/socket.h>
#include <netax25/ax25.h>
#include <netax25/axlib.h>
#include <netax25/axconfig.h>
#include <stdio.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <syslog.h>
#include <sys/types.h>
#include <linux/socket.h>
#include <stdlib.h>
#include <sys/un.h>
#include <string.h>
#include <errno.h>
int main(int argc,char **argv,char **envp) {
int ax25_socket = -1;
unsigned char buffer[512];
struct full_sockaddr_ax25 addr, axconnect ;
char *port ="3";// sm0 port number:3
char *call = "OH2BNS-8";// sm0 callsign
bzero((char *) &addr, sizeof(struct full_sockaddr_ax25));
addr.fsa_ax25.sax25_family = AF_AX25;
addr.fsa_ax25.sax25_ndigis = 1;
if (ax25_config_load_ports() == 0) {
printf( "Problem with axports file");
//return -1;
}
char* ax25port = (char*) ax25_config_get_addr(port);
ax25_aton_entry( call, addr.fsa_ax25.sax25_call.ax25_call);
ax25_aton_entry( ax25port, addr.fsa_digipeater[0].ax25_call);
ax25_socket = socket(AF_AX25, SOCK_SEQPACKET, 0);
if (ax25_socket < -1)
printf( "error in create socket");
if (bind(ax25_socket, (struct sockaddr *)&addr, sizeof(struct full_sockaddr_ax25)) < 0) {
perror("bind--");
return -1;
}
if(listen(ax25_socket,2) != 0)
{
printf("cannot listen on socket!\n");
close(ax25_socket);
return 0;
}
puts("listening");
//bzero((char *) &axconnect, sizeof(struct full_sockaddr_ax25));
int len =sizeof(struct full_sockaddr_ax25);
int temp_sock_desc = accept(ax25_socket, (struct sockaddr*)&axconnect, &len);
if (temp_sock_desc == -1)
{
printf("cannot accept client!\n");
close(ax25_socket);
return 0;
}
return 0;
}
Client code
#include <sys/socket.h>
#include <netax25/ax25.h>
#include <netax25/axlib.h>
#include <netax25/axconfig.h>
#include <stdio.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <syslog.h>
#include <sys/types.h>
#include <linux/socket.h>
#include <stdlib.h>
#include <sys/un.h>
#include <string.h>
#include <errno.h>
int main(int argc, char *argv[])
{
int ax25_socket = -1;
unsigned char buffer[512];
struct full_sockaddr_ax25 axconnect ;
char *port ="3";// sm0 port number:3
char *call ="OH2BNS-8";// sm0 callsign
bzero((char *) &axconnect, sizeof(struct full_sockaddr_ax25));
axconnect.fsa_ax25.sax25_family = AF_AX25;
axconnect.fsa_ax25.sax25_ndigis = 1;
if (ax25_config_load_ports() == 0) {
printf( "Problem with axports file");
//return -1;
}
char* ax25port = (char*) ax25_config_get_addr(port);
ax25_aton_entry( call, axconnect.fsa_ax25.sax25_call.ax25_call);
ax25_aton_entry( ax25port, axconnect.fsa_digipeater[0].ax25_call);
ax25_socket = socket(AF_AX25, SOCK_SEQPACKET, 0);
if (ax25_socket < -1)
printf( "error in create socket");
if (connect(ax25_socket, (struct sockaddr *)&axconnect, sizeof(struct full_sockaddr_ax25)) != 0) {
perror("--");
switch (errno) {
case ECONNREFUSED:
printf("*** Connection refused\r");
break;
case ENETUNREACH:
printf("*** No known route\r");
break;
case EINTR:
printf("*** Connection timed out\r");
break;
default:
printf("ERROR: cannot connect to AX.25 callsign\r");
break;
}
close(ax25_socket);
}
printf("Connected!!\r");
int n = write(ax25_socket,"Message!!!!",18);
if(n = -1)
{
perror("write--");
}
return 0;
}
Simply put, a " No route to host"" would mean that there is no route for the server IP address in the client's routing table. Are you able to ping the server's IP address? Most likely you should not be able to and ping should say that the server is not reachable. If so, then this error has nothing to do with your program, you are probably running into a connectivity issue.
Can you find the entry for your server in the output of "route -n". If there is none, then you should check for a bigger prefix for the subnet of the server. If that also is not present, then you should confirm that you have a default route setup.
To further confirm, I would do the following two tests. First, what happens if you try to run the client/server on the same box? Second, what happens if you try to run the client/server on two boxes (present in the same subnet) and on the same LAN? If you do not see this issue and your application works just fine, then this should confirm that you are running into a connectivity issue.
I know this is an old question, but I would suspect a problem with ax25port - should be something like YOURCALL-0 where YOURCALL matches the HWaddr of an existing ax25 port ( try /sbin/ifconfig | fgrep AX.25
I'm attempting to poll networking device names. I've pieced this together from various snippets,
http://unixhelp.ed.ac.uk/CGI/man-cgi?netdevice+7
http://lists.apple.com/archives/Unix-porting/2002/Apr/msg00134.html
http://ubuntuforums.org/showthread.php?t=1421487
But my output is just gibberish.
#include <stdio.h>
#include <stdlib.h>
#include <net/route.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#define BUFLEN 1024
#define SEQ 9999
int main (int argc, const char* argv[])
{
// File descriptor for socket
int socketfd;
struct ifconf conf;
struct ifreq req[10];
struct ifreq *ifr;
printf("Opening socket...");
socketfd = socket(AF_ROUTE, SOCK_RAW, 0);
if (socketfd >= 0) {
printf(" OK\n");
conf.ifc_len = sizeof(req);
conf.ifc_buf = (__caddr_t) req;
ioctl(socketfd,SIOCGIFCONF,&conf);
printf("Discovering interfaces...\n");
int i;
for (i=0; i<conf.ifc_len/sizeof(req[0]); i++) {
ifr = &conf.ifc_req[i];
printf("%d. %s\n", i+1, req[i].ifr_name);
}
}
else {
printf("Failed!\n");
}
return 0;
}
Output:
Opening socket... OK
Discovering interfaces...
?u???}??Gh???
2. p?9}?
3.
4. v?=?n??u?`?y??]g?<?~?v??
5.
6.
7.
8. ?v?T?
9. ?|?mw??j??v??h??|??v?T00~??v?$?|??|?#
10. T00~??v?$?|??|?#
I tried outputting each char of the ifr_name array one-by-one to see if they were null terminated but that didn't change much. Each iteration of my program outputs something different so this leads me to think I'm referencing something wrong. Can someone provide me some insight as to what I may be doing wrong?
Here's some code I put together for Mac OS X:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <arpa/inet.h>
#include <netinet/in.h>
/* This is defined on Mac OS X */
#ifndef _SIZEOF_ADDR_IFREQ
#define _SIZEOF_ADDR_IFREQ sizeof
#endif
int main (int argc, const char* argv[])
{
// File descriptor for socket
int socketfd;
struct ifconf conf;
char data[4096];
struct ifreq *ifr;
char addrbuf[1024];
int i;
printf("Opening socket...");
socketfd = socket(AF_INET, SOCK_DGRAM, 0);
if (socketfd >= 0) {
printf(" OK\n");
conf.ifc_len = sizeof(data);
conf.ifc_buf = (caddr_t) data;
if (ioctl(socketfd,SIOCGIFCONF,&conf) < 0) {
perror("ioctl");
}
printf("Discovering interfaces...\n");
i = 0;
ifr = (struct ifreq*)data;
while ((char*)ifr < data+conf.ifc_len) {
switch (ifr->ifr_addr.sa_family) {
case AF_INET:
++i;
printf("%d. %s : %s\n", i, ifr->ifr_name, inet_ntop(ifr->ifr_addr.sa_family, &((struct sockaddr_in*)&ifr->ifr_addr)->sin_addr, addrbuf, sizeof(addrbuf)));
break;
#if 0
case AF_INET6:
++i;
printf("%d. %s : %s\n", i, ifr->ifr_name, inet_ntop(ifr->ifr_addr.sa_family, &((struct sockaddr_in6*)&ifr->ifr_addr)->sin6_addr, addrbuf, sizeof(addrbuf)));
break;
#endif
}
ifr = (struct ifreq*)((char*)ifr +_SIZEOF_ADDR_IFREQ(*ifr));
}
close(socketfd);
}
else {
printf(" Failed!\n");
}
return 0;
}
Poll as in you want to be notified if an interface is added or removed? Or polled as in you just want to find out the interface names once from the system? If the latter, take a look at getifaddrs().
Please see http://git.netfilter.org/cgi-bin/gitweb.cgi?p=libmnl.git;a=blob;f=examples/rtnl/rtnl-link-dump.c;hb=HEAD on how to get the list of interfaces on Linux. AF_ROUTE is some BSD thing and the use of ioctl is discouraged on Linux for its apparent limitations (such as to convey multiple addresses on a single interface).
I am trying to obtain the MAC addresses of all of my interface on OSX using C. The common ways to obtain it Linux dont work on BSD - from everything I have seen, you must obtain the interfaces and look for the ones that are of type AF_LINK. My problem is that the LLADDR(sockaddr_dl) gives me a whole bunch of data (which includes my MAC) and I dont know what format the data is in. For example; the following code will output:
Device: en1
link sdl_alen: 101 mac:
31:f8:1e:df:d6:22:1d:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:b0:06:10:00:01:00:00:00:c0:02:10:00:01:00:00:00:00:00:00:00:00:00:00:00:40
:03:10:00:01:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:03:00:6c:6f:30:00:00:00:00:00:00:00:00:00:00:00:00:00:70:03:10:00:01:00:00:00:e0:
02:10:00:01:00:00:
My MAC is bolded. It seems that this is the format all of the time, but I would be a lot more comfortable if I could cast LLADDR(sockaddr_dl) to something. In the net/if_dl.h, LLADDR is defied as:
#define LLADDR(s) ((caddr_t)((s)->sdl_data + (s)->sdl_nlen))
which, as far as I can tell, is saying that the results are of type (void *) - no help.
Other posts like:
Having a problem figuring out how to get Ethernet interface info on Mac OS X using ioctl/SIOCGIFADDR/SIOCGIFCONF?
seem to think they have it figured out, but if you look through the code, you can see it will not work due to sdl_alen not being 6.
int main() {
pcap_if_t *alldevs;
pcap_if_t *d;
pcap_addr_t *alladdrs;
pcap_addr_t *a;
struct sockaddr_dl* link;
char eb[PCAP_ERRBUF_SIZE];
char *addr_buf[40];
if (pcap_findalldevs(&alldevs, eb) == -1) {
printf("no devs found\n");
return(-1);
}
for (d = alldevs; d != NULL; d = d->next) {
printf("Device: %s\n", d->name);
alladdrs = d->addresses;
for (a = alladdrs; a != NULL; a = a->next) {
if(a->addr->sa_family == AF_LINK && a->addr->sa_data != NULL){
// MAC ADDRESS
//struct sockaddr_dl *sdl = (struct sockaddr_dl *) a->addr->sa_data;
link = (struct sockaddr_dl*)a->addr->sa_data;
char mac[link->sdl_alen];
caddr_t macaddr = LLADDR(link);
memcpy(mac, LLADDR(link), link->sdl_alen);
printf("link sdl_alen: %i\n", link->sdl_alen);
int i;
printf("mac: ");
for(i = 0; i<link->sdl_alen; i++){
printf("%02x:", (unsigned char)mac[i]);
}
printf("\n");
}
}
}
}
The problem is that you are casting the sockaddr->sa_data to sockaddr_dl instead of casting the sockaddr itself to sockaddr_dl. Keep in mind that sockaddr_dl is an OS X/BSD thing, so #ifdef that part for portability.
Don't do:
link = (struct sockaddr_dl*)a->addr->sa_data;
Do:
link = (struct sockaddr_dl*)a->addr;
Then you will get the correct sdl_alen and things will work with out any hacks. And if you want to really easily get the name of addresses that may be either AF_INET, AF_INET6, or AF_LINK use getnameinfo():
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <net/if_dl.h>
int get_sock_len(struct sockaddr *sa)
{
switch (sa->sa_family) {
case AF_INET:
return sizeof(struct sockaddr_in);
case AF_INET6:
return sizeof(struct sockaddr_in6);
case AF_LINK:
return sizeof(struct sockaddr_dl);
default:
return -1;
}
}
int get_numeric_address(struct sockaddr *sa, char *outbuf, size_t buflen) {
socklen_t len;
if ((len = get_sock_len(sa)) < 0) {
return -1;
}
if (getnameinfo(sa, len, outbuf, buflen, NULL, 0, NI_NUMERICHOST)) {
return -1;
}
return 0;
}
...
char buf[NI_MAXHOST];
if (!get_numeric_address(sa, buf, sizeof(buf))) { /* For some struct sockaddr *sa */
printf("address: %s\n", buf);
} else {
printf("doh!\n");
}
Here is what I ended up doing:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/sockio.h>
#include <net/if.h>
#include <errno.h>
#include <net/if_dl.h>
#include <pcap.h>
#include "mac.h"
int main() {
printf("en1: %s\n", lookupDeviceMac("vnic0"));
}
unsigned char *lookupDeviceMac(char *dev){
pcap_if_t *alldevs;
pcap_if_t *d;
pcap_addr_t *alladdrs;
pcap_addr_t *a;
struct sockaddr_dl* link;
char eb[PCAP_ERRBUF_SIZE];
char *ret = malloc(6);
if (pcap_findalldevs(&alldevs, eb) == -1) {
printf("%s\n", eb);
return(ret);
}
for (d = alldevs; d != NULL; d = d->next) {
if(strcmp(d->name, dev) == 0){
printf("Device: %s\n", d->name);
alladdrs = d->addresses;
for (a = alladdrs; a != NULL; a = a->next) {
if(a->addr->sa_family == AF_LINK && a->addr->sa_data != NULL){
// MAC ADDRESS
//struct sockaddr_dl *sdl = (struct sockaddr_dl *) a->addr->sa_data;
link = (struct sockaddr_dl*)a->addr->sa_data;
char mac[link->sdl_alen];
caddr_t macaddr = LLADDR(link);
memcpy(mac, LLADDR(link), link->sdl_alen);
if(link->sdl_alen == 6){
// Seen in some sample code
sprintf(ret, "%02x:%02x:%02x:%02x:%02x:%02x",(unsigned char)mac[0],
(unsigned char)mac[1],
(unsigned char)mac[2],
(unsigned char)mac[3],
(unsigned char)mac[4],
(unsigned char)mac[5]);
} else if(link->sdl_alen > 6) {
// This is what happens in OSX 10.6.5
sprintf(ret, "%02x:%02x:%02x:%02x:%02x:%02x",(unsigned char)mac[1],
(unsigned char)mac[2],
(unsigned char)mac[3],
(unsigned char)mac[4],
(unsigned char)mac[5],
(unsigned char)mac[6]);
}
return(ret);
}
}
}
}
}
I was trying to see all devices reported by pcap_findalldevs and ended up here looking for information on interpreting AF_LINK addresses on MAC OS.
I'm used to seeing the struct sockaddr standing in for a interface family and being immediately cast to the appropriate type and not writing code to access *sa_data*.
For what I wanted it was sufficient to use link_ntoa to convert the address to a human readable form.
#import <Foundation/Foundation.h>
#include <pcap.h>
#include <netinet/in.h>
#include <net/if_dl.h>
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
pcap_if_t* allDevs = NULL;
char errbuff[PCAP_ERRBUF_SIZE];
if (pcap_findalldevs(&allDevs, errbuff) <0) {
NSLog(#"Failed with error '%s'", errbuff);
}
else {
for (pcap_if_t* device = allDevs; device != NULL; device = device->next) {
for (pcap_addr_t* address = device->addresses; address != NULL; address = address->next) {
struct sockaddr* sa_addr = address->addr;
if (sa_addr->sa_family == AF_LINK) {
struct sockaddr_dl* link_addr = (struct sockaddr_dl*) sa_addr;
char* linkAddress = link_ntoa(link_addr);
NSLog(#"ntoa %s", linkAddress);
}
}
}
}
pcap_freealldevs(allDevs);
[pool drain];
return 0;
}
Running on my machine I get the following devices with AF_LINK entries.
2011-08-14 02:22:43.024 HomePlugToolHelper[12473:903] ntoa en0:0.16.cb.xx.x.xx
2011-08-14 02:22:43.027 HomePlugToolHelper[12473:903] ntoa fw0:0.16.cb.xx.xx.xx.xx.xx
2011-08-14 02:22:43.028 HomePlugToolHelper[12473:903] ntoa en1:0.16.cb.x.xx.xx
2011-08-14 02:22:43.028 HomePlugToolHelper[12473:903] ntoa lo0