1/* $Id: getifaddr.c,v 1.10 2009/10/28 07:44:43 jmaggard Exp $ */
2/* MiniUPnP project
3 * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
4 * (c) 2006 Thomas Bernard
5 * This software is subject to the conditions detailed
6 * in the LICENCE file provided within the distribution */
7
8#include <stdio.h>
9#include <stdlib.h>
10#include <string.h>
11#include <unistd.h>
12#include <sys/ioctl.h>
13#include <sys/types.h>
14#include <sys/socket.h>
15#include <net/if.h>
16#include <arpa/inet.h>
17#include <netinet/in.h>
18#include <netdb.h>
19#include <errno.h>
20#if defined(sun)
21#include <sys/sockio.h>
22#endif
23
24#include "getifaddr.h"
25#include "log.h"
26
27int
28getifaddr(const char * ifname, char * buf, int len)
29{
30	/* SIOCGIFADDR struct ifreq *  */
31	int s;
32	struct ifreq ifr;
33	int ifrlen;
34	struct sockaddr_in * addr;
35	ifrlen = sizeof(ifr);
36	s = socket(PF_INET, SOCK_DGRAM, 0);
37	if(s < 0)
38	{
39		DPRINTF(E_ERROR, L_GENERAL, "socket(PF_INET, SOCK_DGRAM): %s\n", strerror(errno));
40		return -1;
41	}
42	strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
43	if(ioctl(s, SIOCGIFADDR, &ifr, &ifrlen) < 0)
44	{
45		DPRINTF(E_ERROR, L_GENERAL, "ioctl(s, SIOCGIFADDR, ...): %s\n", strerror(errno));
46		close(s);
47		return -1;
48	}
49	addr = (struct sockaddr_in *)&ifr.ifr_addr;
50	if(!inet_ntop(AF_INET, &addr->sin_addr, buf, len))
51	{
52		DPRINTF(E_ERROR, L_GENERAL, "inet_ntop(): %s\n", strerror(errno));
53		close(s);
54		return -1;
55	}
56	close(s);
57	return 0;
58}
59
60int
61getsysaddr(char * buf, int len)
62{
63	int i;
64	int s = socket(PF_INET, SOCK_STREAM, 0);
65	struct sockaddr_in addr;
66	struct ifreq ifr;
67	int ret = -1;
68
69	for (i=1; i > 0; i++)
70	{
71		ifr.ifr_ifindex = i;
72		if( ioctl(s, SIOCGIFNAME, &ifr) < 0 )
73			break;
74		if(ioctl(s, SIOCGIFADDR, &ifr, sizeof(struct ifreq)) < 0)
75			continue;
76		memcpy(&addr, &ifr.ifr_addr, sizeof(addr));
77		if(strncmp(inet_ntoa(addr.sin_addr), "127.", 4) == 0)
78			continue;
79		if(!inet_ntop(AF_INET, &addr.sin_addr, buf, len))
80		{
81			DPRINTF(E_ERROR, L_GENERAL, "inet_ntop(): %s\n", strerror(errno));
82			close(s);
83			break;
84		}
85		ret = 0;
86		break;
87	}
88	close(s);
89
90	return(ret);
91}
92
93int
94getsyshwaddr(char * buf, int len)
95{
96	struct if_nameindex *ifaces, *if_idx;
97	unsigned char mac[6];
98	struct ifreq ifr;
99	int fd;
100	int ret = -1;
101
102	memset(&mac, '\0', sizeof(mac));
103	/* Get the spatially unique node identifier */
104	fd = socket(AF_INET, SOCK_DGRAM, 0);
105	if( fd < 0 )
106		return(ret);
107
108	ifaces = if_nameindex();
109	if(!ifaces)
110		return(ret);
111
112	for(if_idx = ifaces; if_idx->if_index; if_idx++)
113	{
114		strncpy(ifr.ifr_name, if_idx->if_name, IFNAMSIZ);
115		if(ioctl(fd, SIOCGIFFLAGS, &ifr) < 0)
116			continue;
117		if(ifr.ifr_ifru.ifru_flags & IFF_LOOPBACK)
118			continue;
119		if( ioctl(fd, SIOCGIFHWADDR, &ifr) < 0 )
120			continue;
121		if( MACADDR_IS_ZERO(&ifr.ifr_hwaddr.sa_data) )
122			continue;
123		ret = 0;
124		break;
125	}
126	if_freenameindex(ifaces);
127	close(fd);
128
129	if(ret == 0)
130	{
131		if(len > 12)
132		{
133			memmove(mac, ifr.ifr_hwaddr.sa_data, 6);
134			sprintf(buf, "%02x%02x%02x%02x%02x%02x",
135			        mac[0]&0xFF, mac[1]&0xFF, mac[2]&0xFF,
136			        mac[3]&0xFF, mac[4]&0xFF, mac[5]&0xFF);
137		}
138		else if(len == 6)
139		{
140			memmove(buf, ifr.ifr_hwaddr.sa_data, 6);
141		}
142	}
143	return ret;
144}
145
146int
147get_remote_mac(struct in_addr ip_addr, unsigned char * mac)
148{
149	struct in_addr arp_ent;
150	FILE * arp;
151	char remote_ip[16];
152	int matches, hwtype, flags;
153	memset(mac, 0xFF, 6);
154
155 	arp = fopen("/proc/net/arp", "r");
156	if( !arp )
157		return 1;
158	while( !feof(arp) )
159	{
160	        matches = fscanf(arp, "%s 0x%X 0x%X %hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
161		                      remote_ip, &hwtype, &flags,
162		                      &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]);
163		if( matches != 9 )
164			continue;
165		inet_pton(AF_INET, remote_ip, &arp_ent);
166		if( ip_addr.s_addr == arp_ent.s_addr )
167			break;
168		mac[0] = 0xFF;
169	}
170	fclose(arp);
171
172	if( mac[0] == 0xFF )
173	{
174		memset(mac, 0xFF, 6);
175		return 1;
176	}
177
178	return 0;
179}
180