1 
2 /* ********************************************************************	*
3  * ni_lifreq.c	version 0.05 3-7-09					*
4  *									*
5  *     COPYRIGHT 2008-2009 Michael Robinton <michael@bizsystems.com>	*
6  *									*
7  * This program is free software; you can redistribute it and/or modify	*
8  * it under the terms of either:					*
9  *									*
10  *  a) the GNU General Public License as published by the Free		*
11  *  Software Foundation; either version 2, or (at your option) any	*
12  *  later version, or							*
13  *									*
14  *  b) the "Artistic License" which comes with this distribution.	*
15  *									*
16  * This program is distributed in the hope that it will be useful,	*
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of	*
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See either	*
19  * the GNU General Public License or the Artistic License for more 	*
20  * details.								*
21  *									*
22  * You should have received a copy of the Artistic License with this	*
23  * distribution, in the file named "Artistic".  If not, I'll be glad 	*
24  * to provide one.							*
25  *									*
26  * You should also have received a copy of the GNU General Public 	*
27  * License along with this program in the file named "Copying". If not, *
28  * write to the 							*
29  *									*
30  *	Free Software Foundation, Inc.					*
31  *	59 Temple Place, Suite 330					*
32  *	Boston, MA  02111-1307, USA					*
33  *									*
34  * or visit their web page on the internet at:				*
35  *									*
36  *	http://www.gnu.org/copyleft/gpl.html.				*
37  * ********************************************************************	*
38  *
39  *
40 
41   DESCRIPTION
42     Accessor functions for 'lifconf' and 'lifreq'
43  *
44  */
45 
46 #include "localconf.h"
47 
48 #ifdef HAVE_STRUCT_LIFREQ
49 
50 #ifndef LIFC_TEMPORARY
51 #define LIFC_TEMPORARY 0
52 #endif
53 #ifndef LIFC_ALLZONES
54 #define LIFC_ALLZONES 0
55 #endif
56 
57 static int
_ni_get_ifaddrs(int fd,struct ifaddrs * thisif,struct lifreq * ifr,...)58 _ni_get_ifaddrs(int fd, struct ifaddrs * thisif, struct lifreq * ifr,...)
59 {
60     int cmd;
61 
62     if (ioctl(fd,SIOCGLIFFLAGS,ifr) < 0)
63 	return -1;
64     thisif->ifa_flags = (u_int)(ifr->lifr_flags & 0xFFFFu);
65 
66     if (ioctl(fd,SIOCGLIFNETMASK,ifr) != -1) {
67 	if ((thisif->ifa_netmask = ni_memdup(&(ifr->lifr_addr),
68 				    SA_LEN(((struct sockaddr *)&ifr->lifr_addr)))) == NULL)
69 	    return -1;
70     }
71     if (thisif->ifa_flags & (IFF_POINTOPOINT | IFF_BROADCAST)) {
72 	if (thisif->ifa_flags & IFF_POINTOPOINT)
73 	    cmd = SIOCGLIFDSTADDR;
74 	else
75 	    cmd = SIOCGLIFBRDADDR;
76 
77 	if (ioctl(fd,cmd,ifr) != -1) {
78 	    if ((thisif->ifa_dstaddr = ni_memdup(&(ifr->lifr_addr),
79 					SA_LEN(((struct sockaddr *)&ifr->lifr_addr)))) == NULL)
80 		return -1;
81 	}
82     }
83     return 0;
84 }
85 
86 /*	nifp points to me	*/
87 static int
ni_lifreq_gifaddrs(struct ifaddrs ** ifap,struct ni_ifconf_flavor * nifp)88 ni_lifreq_gifaddrs(struct ifaddrs **ifap, struct ni_ifconf_flavor * nifp)
89 {
90     struct lifconf ifc;
91     struct lifreq * ifr;
92     struct ifaddrs * thisif, * lastif = NULL;
93     struct sockaddr * sa;
94     int fd, af, inc, ret, n;
95 
96     *ifap = NULL;
97 
98     if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
99 	return errno;
100 
101     if (nifp->getifreqs(fd,&ifc) == NULL) {
102 	close(fd);
103 	return errno;
104     }
105 
106     ifr = ifc.lifc_req;
107 
108     for (n = 0; n < ifc.lifc_len; n += sizeof(struct lifreq)) {
109 	if ((thisif = calloc(1, sizeof(struct ifaddrs))) == NULL) {
110 	    errno = ENOMEM;
111 	    goto error_out;
112 	}
113 	if (lastif == NULL) 	/* taken care of in init statement */
114 	    *ifap = thisif;
115 	else
116 	    lastif->ifa_next = thisif;
117 
118 	if ((thisif->ifa_name = strdup(ifr->lifr_name)) == NULL) {
119 	    errno = ENOMEM;
120 	    goto error_out;
121 	}
122 
123 	af = ifr->lifr_addr.ss_family;
124 	if ((thisif->ifa_addr = ni_memdup(&(ifr->lifr_addr),
125 				    SA_LEN(((struct sockaddr *)&ifr->lifr_addr)))) == NULL)
126 	    goto error_out;
127 
128 	if (af == AF_INET) {
129 
130             fd = ni_clos_reopn_dgrm(fd,af);
131 	    if (_ni_get_ifaddrs(fd,thisif,ifr) < 0)
132 	        goto error_out;
133 
134 	}	/* == AF_INET	*/
135 #ifdef LOCAL_SIZEOF_SOCKADDR_IN6
136 	else if (af == AF_INET6) {
137 
138             fd = ni_clos_reopn_dgrm(fd,af);
139 	    if (_ni_get_ifaddrs(fd,thisif,ifr) < 0)
140 	        goto error_out;
141 
142 	}	/* == AF_INET6	*/
143 #endif
144 /*	for AF_LINK, AF_PACKET nothing is used except the contents of the addr record	*/
145 
146 	lastif = thisif;
147 	ifr = (struct lifreq *)((char *)ifr + sizeof(struct lifreq));
148     }
149     close(fd);
150     free(ifc.lifc_req);		/* free ifreq	*/
151     return nifp->ni_type;	/* return family type */
152 
153   error_out:
154     ret = errno;	/* preserve errno	*/
155     free(ifc.lifc_req);
156     ni_freeifaddrs(*ifap);
157     close(fd);
158     errno = ret;
159     return -1;
160 }
161 
162 static void *
_ni_getifreqs(int fd,void * vifc)163 _ni_getifreqs(int fd, void * vifc)
164 {
165     int n, af, size;
166     struct lifconf * ifc = vifc;
167     struct lifnum lifn;
168     void * buf;
169 
170     bzero(ifc,sizeof(struct lifconf));
171     errno = ENOSYS;
172 
173     n = 2;
174     buf = NULL;
175     while (1) {
176         size = n * PAGE_SIZE;
177         if (size > NI_IFREQ_MEM_MAX) {
178             free(buf);
179             errno = ENOMEM;
180             return NULL;
181         }
182         buf = realloc(buf, size);
183         if (buf == NULL) {
184             free(ifc->lifc_buf);
185             errno = ENOMEM;
186             return NULL;
187         }
188         ifc->lifc_family = AF_UNSPEC;
189         ifc->lifc_flags =  LIFC_NOXMIT | LIFC_TEMPORARY | LIFC_ALLZONES;
190         ifc->lifc_buf = buf;
191         ifc->lifc_len = size;
192         if (ioctl( fd, SIOCGLIFCONF, ifc) < 0 && errno != EINVAL) {
193             free(buf);
194             return NULL;
195         }
196         if (ifc->lifc_len < size - PAGE_SIZE)
197             break;
198         n *= 2;
199 /*
200 printf("n %d, len %d, buf %d, ifclen %d, ifr %u\n",size,buf,ifc->lifc_len,ifc->lifc_req);
201  */
202     }
203     return ifc->lifc_req;
204 }
205 
206 static void
_ni_common_flags(u_int64_t flags)207 _ni_common_flags(u_int64_t flags)
208 {
209     int i, n;
210 
211 #include "ni_IFF_inc.c"
212 
213     if (flags & IFF_UP)
214         printf("UP ");
215     else
216         printf("DOWN ");
217     n = sizeof(ni_iff_tab) / sizeof(ni_iff_t);
218     for (i=0;i<n;i++) {
219         if (flags & ni_iff_tab[i].iff_val)
220             printf("%s ",ni_iff_tab[i].iff_nam);
221     }
222 }
223 
224 int
ni_flav_lifreq_developer(void * ifcee)225 ni_flav_lifreq_developer(void * ifcee)
226 {
227     /*	ifcee unused	*/
228     int n, fd = -1, af, namegood, macgood;
229     u_int64_t flags;
230     struct lifconf lifc;
231     struct lifreq * ifr;
232     struct ifreq mifr;
233     unsigned char mac[6] = {0x0,0x0,0x0,0xfa,0x11,0xed};
234     unsigned char altmac[6], * macp;
235     char namebuf[NI_MAXHOST];
236     struct sockaddr_storage laddr;
237     struct sockaddr_in * sin;
238     struct sockaddr_in6 * sin6;
239 
240     lifc.lifc_family = AF_UNSPEC;	/* stuff AF for ni_getifreqs	*/
241     af = AF_INET;
242     if ((fd = socket(af,SOCK_DGRAM,0)) < 0)
243     	return errno;
244 
245     if (_ni_getifreqs(fd,&lifc) == NULL) {
246 	close(fd);
247 	return errno;
248     }
249     ifr = lifc.lifc_req;
250     for (n = 0; n < lifc.lifc_len; n += sizeof(struct lifreq)) {
251         namegood = macgood = 0;
252 /* BSD pretty much assumes that SA_LEN is defined, if not fudge it	*/
253 
254 	af = ifr->lifr_addr.ss_family;
255 	printf("%s\t",ifr->lifr_name);
256 
257 	if (af == AF_INET) {
258 	    fd = ni_clos_reopn_dgrm(fd,AF_INET);
259 	    if (ioctl(fd, SIOCGLIFFLAGS,ifr) != -1) {
260 		flags = ifr->lifr_flags;
261 		printf("flags=%0llx<",flags);
262                 _ni_common_flags(flags);
263 		if (flags == 0)
264 		    printf(" ");
265 		printf("\b> ");
266 	    }
267 	    if (ioctl(fd,SIOCGLIFMETRIC,ifr) != -1 );
268 	    	printf("metric %d ",ifr->lifr_metric);
269 	    if (ioctl(fd,SIOCGLIFMTU,ifr) != -1 )
270 	    	printf("mtu %d",ifr->lifr_mtu);
271 	    printf("\n\t");
272 
273 	    if (ioctl(fd,SIOCGLIFADDR,ifr) != -1 ) {
274 	        sin = (struct sockaddr_in *) &ifr->lifr_addr;
275 #ifdef HAVE_GETNAMEINFO
276 		if (getnameinfo(&sin->sin_addr,
277 		    LOCAL_SIZEOF_SOCKADDR_IN,namebuf,NI_MAXHOST,NULL,0,NI_NUMERICHOST) != 0)
278 #endif
279 		    strcpy(namebuf,inet_ntoa(sin->sin_addr));
280 	    	printf("address %s\t",namebuf);
281 	    }
282 	    if (ioctl(fd,SIOCGLIFNETMASK,ifr) != -1 ) {
283 	        sin = (struct sockaddr_in *) &ifr->lifr_addr;
284 		printf("mask 0x%lx\t",(unsigned long)ntohl(sin->sin_addr.s_addr));
285             }
286 /* want to include here.... flags & IFF_BROADCAST	*/
287 	    if (ioctl(fd,SIOCGLIFBRDADDR,ifr) != -1) {
288 	        sin = (struct sockaddr_in *) &ifr->lifr_addr;
289                 strcpy(namebuf,inet_ntoa(sin->sin_addr));
290 	    	printf("netmask %s\t",namebuf);
291             }
292 	}
293 	else if (af == AF_INET6) {
294 	    fd = ni_clos_reopn_dgrm(fd,AF_INET6);
295 	    if (ioctl(fd,SIOCGLIFADDR,ifr) != -1 ) {
296 	        sin6 = (struct sockaddr_in6 *)&ifr->lifr_addr;
297 #ifdef HAVE_GETNAMEINFO
298 		if (getnameinfo(&ifr->ni_saddr,LOCAL_SIZEOF_SOCKADDR_IN6,namebuf,NI_MAXHOST,NULL,0,NI_NUMERICHOST) != 0)
299 #endif
300 		    strcpy(namebuf,inet_ntop(AF_INET6,&sin6->sin6_addr,namebuf,NI_MAXHOST));
301                 namegood = 1;
302             }
303 
304 	    if (ioctl(fd,SIOCGLIFFLAGS,ifr) < 0 ) {
305 	        printf("\nflags error: %d %s",errno, strerror(errno));
306 	    }
307             else {
308 		flags = ifr->lifr_flags;
309                 printf("flags=%0llx<",flags);
310                 _ni_common_flags(flags);
311 	        if (flags == 0)
312                     printf(" ");
313                 printf("\b> ");
314             }
315             if (ioctl(fd,SIOCGLIFMETRIC,ifr) != -1 );
316 		printf("metric %d ",ifr->lifr_metric);
317 	    if (ioctl(fd,SIOCGLIFMTU,ifr) != -1 )
318 		printf("mtu %d",ifr->lifr_mtu);
319         }
320         printf("\n\t");
321         if (namegood)
322             printf("address %s\n\t",namebuf);
323 
324 	printf("af=%d sz=%d ",af,sizeof(struct lifreq));
325 
326 #if defined SIOCENADDR
327 	if (ioctl(fd,SIOCENADDR,ifr) != -1)
328 	    macgood = 1;
329 #endif
330 	if (macgood == 1)
331             macp = (unsigned char *)&ifr->lifr_enaddr;
332 	else {
333 	    strlcpy(mifr.ifr_name,ifr->lifr_name,IFNAMSIZ);
334 	    close(fd);
335 	    fd = -1;
336 	    if ((macp = ni_fallbackhwaddr(af,&mifr)) != NULL)
337 	        macgood = 1;
338         }
339         if (macgood)
340 	    printf("MAC addr %02X:%02X:%02X:%02X:%02X:%02X",
341 	        macp[0],macp[1],macp[2],macp[3],macp[4],macp[5]);
342 
343 	printf("\n");
344 	ifr++;
345     }
346     close(fd);
347     free(lifc.lifc_req);
348     return 0;
349 }
350 
351 static struct ni_ifconf_flavor ni_flavor_lifreq = {
352     .ni_type		= NI_LIFREQ,
353     .siocgifindex	= SIOCGLIFINDEX,
354     .siocsifaddr	= SIOCSLIFADDR,
355     .siocgifaddr	= SIOCGLIFADDR,
356     .siocdifaddr	= SIOCLIFREMOVEIF,
357     .siocaifaddr	= SIOCLIFADDIF,
358     .siocsifdstaddr	= SIOCSLIFDSTADDR,
359     .siocgifdstaddr	= SIOCGLIFDSTADDR,
360     .siocsifflags	= SIOCSLIFFLAGS,
361     .siocgifflags	= SIOCGLIFFLAGS,
362     .siocsifmtu		= SIOCSLIFMTU,
363     .siocgifmtu		= SIOCGLIFMTU,
364     .siocsifbrdaddr	= SIOCSLIFBRDADDR,
365     .siocgifbrdaddr	= SIOCGLIFBRDADDR,
366     .siocsifnetmask	= SIOCGLIFNETMASK,
367     .siocgifnetmask	= SIOCGLIFNETMASK,
368     .siocsifmetric	= SIOCSLIFMETRIC,
369     .siocgifmetric	= SIOCGLIFMETRIC,
370     .ifr_offset		= NI_LIFREQ_OFFSET,
371     .gifaddrs		= ni_lifreq_gifaddrs,
372     .fifaddrs		= ni_freeifaddrs,
373     .refreshifr		= NULL,
374     .getifreqs		= _ni_getifreqs,
375     .developer		= ni_flav_lifreq_developer,
376 };
377 
378 void
ni_lifreq_ctor()379 ni_lifreq_ctor()
380 {
381     ni_ifcf_register(&ni_flavor_lifreq);
382 }
383 
384 #else
385 
386 void
ni_lifreq_ctor()387 ni_lifreq_ctor()
388 {
389     return;
390 }
391 
392 #endif	/* have lifreq */
393 
394