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