Deleted Added
sdiff udiff text old ( 78410 ) new ( 81634 )
full compact
1/*-
2 * Copyright (c) 1998 Brian Somers <brian@Awfulhak.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright

--- 9 unchanged lines hidden (view full) ---

18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD: head/usr.sbin/ppp/iface.c 81634 2001-08-14 16:05:52Z brian $
27 */
28
29#include <sys/param.h>
30#include <sys/socket.h>
31#include <netinet/in.h>
32#include <net/if.h>
33#include <net/if_dl.h>
34#include <net/if_var.h>
35#include <net/route.h>
36#include <arpa/inet.h>
37#include <netinet/in_systm.h>
38#include <netinet/in_var.h>
39#include <netinet/ip.h>
40#ifndef NOINET6
41#include <netinet6/nd6.h>
42#endif
43#include <sys/un.h>
44
45#include <errno.h>
46#include <string.h>
47#include <stdio.h>
48#include <stdlib.h>
49#include <sys/ioctl.h>
50#include <sys/sysctl.h>

--- 9 unchanged lines hidden (view full) ---

60#include "timer.h"
61#include "fsm.h"
62#include "iplist.h"
63#include "lqr.h"
64#include "hdlc.h"
65#include "throughput.h"
66#include "slcompress.h"
67#include "descriptor.h"
68#include "ncpaddr.h"
69#include "ip.h"
70#include "ipcp.h"
71#include "filter.h"
72#include "lcp.h"
73#include "ccp.h"
74#include "link.h"
75#include "mp.h"
76#ifndef NORADIUS
77#include "radius.h"
78#endif
79#include "ipv6cp.h"
80#include "ncp.h"
81#include "bundle.h"
82#include "prompt.h"
83#include "iface.h"
84
85
86struct iface *
87iface_Create(const char *name)
88{
89 int mib[6], maxtries, err;
90 size_t needed, namelen;
91 char *buf, *ptr, *end;
92 struct if_msghdr *ifm;
93 struct ifa_msghdr *ifam;
94 struct sockaddr_dl *dl;
95 struct sockaddr *sa[RTAX_MAX];
96 struct iface *iface;
97 struct iface_addr *addr;
98
99 mib[0] = CTL_NET;
100 mib[1] = PF_ROUTE;
101 mib[2] = 0;
102 mib[3] = 0;
103 mib[4] = NET_RT_IFLIST;
104 mib[5] = 0;
105
106 maxtries = 20;
107 err = 0;
108 do {
109 if (maxtries-- == 0 || (err && err != ENOMEM)) {
110 fprintf(stderr, "iface_Create: sysctl: %s\n", strerror(err));
111 return NULL;
112 }
113
114 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
115 fprintf(stderr, "iface_Create: sysctl: estimate: %s\n",
116 strerror(errno));
117 return NULL;
118 }
119
120 if ((buf = (char *)malloc(needed)) == NULL) {
121 fprintf(stderr, "iface_Create: malloc failed: %s\n", strerror(errno));
122 return NULL;
123 }
124
125 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
126 err = errno;
127 free(buf);
128 buf = NULL;
129 }

--- 14 unchanged lines hidden (view full) ---

144 if (iface == NULL) {
145 fprintf(stderr, "iface_Create: malloc: %s\n", strerror(errno));
146 return NULL;
147 }
148 iface->name = strdup(name);
149 iface->index = ifm->ifm_index;
150 iface->flags = ifm->ifm_flags;
151 iface->mtu = 0;
152 iface->addrs = 0;
153 iface->addr = NULL;
154 }
155 ptr += ifm->ifm_msglen; /* First ifa_msghdr */
156 for (; ptr < end; ptr += ifam->ifam_msglen) {
157 ifam = (struct ifa_msghdr *)ptr; /* Next if address */
158
159 if (ifam->ifam_type != RTM_NEWADDR) /* finished this if */
160 break;
161
162 if (iface != NULL && ifam->ifam_addrs & RTA_IFA) {
163 /* Found a configured interface ! */
164 iface_ParseHdr(ifam, sa);
165
166 if (sa[RTAX_IFA] && (sa[RTAX_IFA]->sa_family == AF_INET
167#ifndef NOINET6
168 || sa[RTAX_IFA]->sa_family == AF_INET6
169#endif
170 )) {
171 /* Record the address */
172
173 addr = (struct iface_addr *)
174 realloc(iface->addr, (iface->addrs + 1) * sizeof iface->addr[0]);
175 if (addr == NULL)
176 break;
177 iface->addr = addr;
178
179 addr += iface->addrs;
180 iface->addrs++;
181
182 ncprange_setsa(&addr->ifa, sa[RTAX_IFA], sa[RTAX_NETMASK]);
183 if (sa[RTAX_BRD])
184 ncpaddr_setsa(&addr->peer, sa[RTAX_BRD]);
185 else
186 ncpaddr_init(&addr->peer);
187 }
188 }
189 }
190 }
191
192 free(buf);
193
194 return iface;
195}
196
197static int
198iface_addr_Zap(const char *name, struct iface_addr *addr, int s)
199{
200 struct ifaliasreq ifra;
201#ifndef NOINET6
202 struct in6_aliasreq ifra6;
203#endif
204 struct sockaddr_in *me4, *msk4, *peer4;
205 struct sockaddr_storage ssme, sspeer, ssmsk;
206 int res;
207
208 ncprange_getsa(&addr->ifa, &ssme, &ssmsk);
209 ncpaddr_getsa(&addr->peer, &sspeer);
210 res = 0;
211
212 switch (ncprange_family(&addr->ifa)) {
213 case AF_INET:
214 memset(&ifra, '\0', sizeof ifra);
215 strncpy(ifra.ifra_name, name, sizeof ifra.ifra_name - 1);
216
217 me4 = (struct sockaddr_in *)&ifra.ifra_addr;
218 memcpy(me4, &ssme, sizeof *me4);
219
220 msk4 = (struct sockaddr_in *)&ifra.ifra_mask;
221 memcpy(msk4, &ssmsk, sizeof *msk4);
222
223 peer4 = (struct sockaddr_in *)&ifra.ifra_broadaddr;
224 if (ncpaddr_family(&addr->peer) == AF_UNSPEC) {
225 peer4->sin_family = AF_INET;
226 peer4->sin_len = sizeof(*peer4);
227 peer4->sin_addr.s_addr = INADDR_NONE;
228 } else
229 memcpy(peer4, &sspeer, sizeof *peer4);
230
231 res = ID0ioctl(s, SIOCDIFADDR, &ifra);
232 break;
233
234#ifndef NOINET6
235 case AF_INET6:
236 memset(&ifra6, '\0', sizeof ifra6);
237 strncpy(ifra6.ifra_name, name, sizeof ifra6.ifra_name - 1);
238
239 memcpy(&ifra6.ifra_addr, &ssme, sizeof ifra6.ifra_addr);
240 memcpy(&ifra6.ifra_prefixmask, &ssmsk, sizeof ifra6.ifra_prefixmask);
241 ifra6.ifra_prefixmask.sin6_family = AF_UNSPEC;
242 if (ncpaddr_family(&addr->peer) == AF_UNSPEC)
243 ifra6.ifra_dstaddr.sin6_family = AF_UNSPEC;
244 else
245 memcpy(&ifra6.ifra_dstaddr, &sspeer, sizeof ifra6.ifra_dstaddr);
246 ifra6.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
247 ifra6.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
248
249 res = ID0ioctl(s, SIOCDIFADDR_IN6, &ifra6);
250 break;
251#endif
252 }
253
254 if (res == -1) {
255 char dst[40];
256 const char *end =
257#ifndef NOINET6
258 ncprange_family(&addr->ifa) == AF_INET6 ? "_IN6" :
259#endif
260 "";
261
262 if (ncpaddr_family(&addr->peer) == AF_UNSPEC)
263 log_Printf(LogWARN, "iface rm: ioctl(SIOCDIFADDR%s, %s): %s\n",
264 end, ncprange_ntoa(&addr->ifa), strerror(errno));
265 else {
266 snprintf(dst, sizeof dst, "%s", ncpaddr_ntoa(&addr->peer));
267 log_Printf(LogWARN, "iface rm: ioctl(SIOCDIFADDR%s, %s -> %s): %s\n",
268 end, ncprange_ntoa(&addr->ifa), dst, strerror(errno));
269 }
270 }
271
272 return res != -1;
273}
274
275static void
276iface_addr_Add(const char *name, struct iface_addr *addr, int s)
277{
278 struct ifaliasreq ifra;
279#ifndef NOINET6
280 struct in6_aliasreq ifra6;
281#endif
282 struct sockaddr_in *me4, *msk4, *peer4;
283 struct sockaddr_storage ssme, sspeer, ssmsk;
284 int res;
285
286 ncprange_getsa(&addr->ifa, &ssme, &ssmsk);
287 ncpaddr_getsa(&addr->peer, &sspeer);
288 res = 0;
289
290 switch (ncprange_family(&addr->ifa)) {
291 case AF_INET:
292 memset(&ifra, '\0', sizeof ifra);
293 strncpy(ifra.ifra_name, name, sizeof ifra.ifra_name - 1);
294
295 me4 = (struct sockaddr_in *)&ifra.ifra_addr;
296 memcpy(me4, &ssme, sizeof *me4);
297
298 msk4 = (struct sockaddr_in *)&ifra.ifra_mask;
299 memcpy(msk4, &ssmsk, sizeof *msk4);
300
301 peer4 = (struct sockaddr_in *)&ifra.ifra_broadaddr;
302 if (ncpaddr_family(&addr->peer) == AF_UNSPEC) {
303 peer4->sin_family = AF_INET;
304 peer4->sin_len = sizeof(*peer4);
305 peer4->sin_addr.s_addr = INADDR_NONE;
306 } else
307 memcpy(peer4, &sspeer, sizeof *peer4);
308
309 res = ID0ioctl(s, SIOCAIFADDR, &ifra);
310 break;
311
312#ifndef NOINET6
313 case AF_INET6:
314 memset(&ifra6, '\0', sizeof ifra6);
315 strncpy(ifra6.ifra_name, name, sizeof ifra6.ifra_name - 1);
316
317 memcpy(&ifra6.ifra_addr, &ssme, sizeof ifra6.ifra_addr);
318 memcpy(&ifra6.ifra_prefixmask, &ssmsk, sizeof ifra6.ifra_prefixmask);
319 if (ncpaddr_family(&addr->peer) == AF_UNSPEC)
320 ifra6.ifra_dstaddr.sin6_family = AF_UNSPEC;
321 else
322 memcpy(&ifra6.ifra_dstaddr, &sspeer, sizeof ifra6.ifra_dstaddr);
323 ifra6.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
324 ifra6.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
325
326 res = ID0ioctl(s, SIOCAIFADDR_IN6, &ifra6);
327 break;
328#endif
329 }
330
331 if (res == -1) {
332 char dst[40];
333 const char *end =
334#ifndef NOINET6
335 ncprange_family(&addr->ifa) == AF_INET6 ? "_IN6" :
336#endif
337 "";
338
339 if (ncpaddr_family(&addr->peer) == AF_UNSPEC)
340 log_Printf(LogWARN, "iface add: ioctl(SIOCAIFADDR%s, %s): %s\n",
341 end, ncprange_ntoa(&addr->ifa), strerror(errno));
342 else {
343 snprintf(dst, sizeof dst, "%s", ncpaddr_ntoa(&addr->peer));
344 log_Printf(LogWARN, "iface add: ioctl(SIOCDIFADDR%s, %s -> %s): %s\n",
345 end, ncprange_ntoa(&addr->ifa), dst, strerror(errno));
346 }
347 }
348}
349
350
351void
352iface_Clear(struct iface *iface, struct ncp *ncp, int family, int how)
353{
354 int addrs, af, inskip, in6skip, n, s4 = -1, s6 = -1, *s;
355
356 if (iface->addrs) {
357 inskip = in6skip = how == IFACE_CLEAR_ALL ? 0 : 1;
358 addrs = 0;
359
360 for (n = 0; n < iface->addrs; n++) {
361 af = ncprange_family(&iface->addr[n].ifa);
362 if (family == 0 || family == af) {
363 if (!iface->addr[n].system && (how & IFACE_SYSTEM))
364 continue;
365 switch (af) {
366 case AF_INET:
367 if (inskip) {
368 inskip = 0;
369 continue;
370 }
371 s = &s4;
372 break;
373
374#ifndef NOINET6
375 case AF_INET6:
376 if (in6skip) {
377 in6skip = 0;
378 continue;
379 }
380 s = &s6;
381 break;
382#endif
383 }
384
385 if (*s == -1 && (*s = ID0socket(af, SOCK_DGRAM, 0)) == -1)
386 log_Printf(LogERROR, "iface_Clear: socket(): %s\n", strerror(errno));
387 else if (iface_addr_Zap(iface->name, iface->addr + n, *s)) {
388 ncp_IfaceAddrDeleted(ncp, iface->addr + n);
389 bcopy(iface->addr + n + 1, iface->addr + n,
390 (iface->addrs - n - 1) * sizeof *iface->addr);
391 iface->addrs--;
392 n--;
393 }
394 }
395 }
396
397 /* Don't bother realloc()ing - we have little to gain */
398
399 if (s4)
400 close(s4);
401 if (s6)
402 close(s6);
403 }
404}
405
406int
407iface_Add(struct iface *iface, struct ncp *ncp, const struct ncprange *ifa,
408 const struct ncpaddr *peer, int how)
409{
410 int af, n, s, width;
411 struct ncpaddr ifaddr, ncplocal;
412 struct iface_addr *addr;
413
414 af = ncprange_family(ifa);
415 if ((s = ID0socket(af, SOCK_DGRAM, 0)) == -1) {
416 log_Printf(LogERROR, "iface_Add: socket(): %s\n", strerror(errno));
417 return 0;
418 }
419 ncprange_getaddr(ifa, &ncplocal);
420
421 for (n = 0; n < iface->addrs; n++) {
422 if (ncprange_contains(&iface->addr[n].ifa, &ncplocal)) {
423 if (!(how & IFACE_FORCE_ADD)) {
424 close(s);
425 return 0; /* errno = EEXIST; */
426 }
427
428 if (ncprange_equal(&iface->addr[n].ifa, ifa) &&
429 ncpaddr_equal(&iface->addr[n].peer, peer)) {
430 close(s);
431 return 1; /* Already there */
432 }
433
434 width =
435#ifndef NOINET6
436 (af == AF_INET6) ? 128 :
437#endif
438 32;
439 iface_addr_Zap(iface->name, iface->addr + n, s);
440 ncprange_setwidth(&iface->addr[n].ifa, width);
441 ncprange_getaddr(&iface->addr[n].ifa, &ifaddr);
442 if (ncpaddr_equal(&ifaddr, &ncplocal))
443 ncpaddr_copy(&iface->addr[n].peer, peer);
444 else
445 ncpaddr_init(&iface->addr[n].peer);
446 iface_addr_Add(iface->name, iface->addr + n, s);
447 if (ncpaddr_equal(&ifaddr, &ncplocal)) {
448 close(s);
449 ncp_IfaceAddrAdded(ncp, iface->addr + n);
450 return 1;
451 }
452 }
453 }
454
455 addr = (struct iface_addr *)realloc
456 (iface->addr, (iface->addrs + 1) * sizeof iface->addr[0]);
457 if (addr == NULL) {
458 log_Printf(LogERROR, "iface_inAdd: realloc: %s\n", strerror(errno));
459 close(s);
460 return 0;
461 }
462 iface->addr = addr;
463
464 if (how & IFACE_ADD_FIRST) {
465 /* Stuff it at the start of our list */
466 n = 0;
467 bcopy(iface->addr, iface->addr + 1, iface->addrs * sizeof *iface->addr);
468 } else
469 n = iface->addrs;
470
471 iface->addrs++;
472 ncprange_copy(&iface->addr[n].ifa, ifa);
473 ncpaddr_copy(&iface->addr[n].peer, peer);
474 iface->addr[n].system = !!(how & IFACE_SYSTEM);
475 iface_addr_Add(iface->name, iface->addr + n, s);
476
477 close(s);
478 ncp_IfaceAddrAdded(ncp, iface->addr + n);
479
480 return 1;
481}
482
483int
484iface_Delete(struct iface *iface, struct ncp *ncp, const struct ncpaddr *del)
485{
486 struct ncpaddr found;
487 int n, res, s;
488
489 if ((s = ID0socket(ncpaddr_family(del), SOCK_DGRAM, 0)) == -1) {
490 log_Printf(LogERROR, "iface_Delete: socket(): %s\n", strerror(errno));
491 return 0;
492 }
493
494 for (n = res = 0; n < iface->addrs; n++) {
495 ncprange_getaddr(&iface->addr[n].ifa, &found);
496 if (ncpaddr_equal(&found, del)) {
497 iface_addr_Zap(iface->name, iface->addr + n, s);
498 ncp_IfaceAddrDeleted(ncp, iface->addr + n);
499 bcopy(iface->addr + n + 1, iface->addr + n,
500 (iface->addrs - n - 1) * sizeof *iface->addr);
501 iface->addrs--;
502 res = 1;
503 break;
504 }
505 }
506
507 close(s);
508
509 return res;
510}
511
512#define IFACE_ADDFLAGS 1
513#define IFACE_DELFLAGS 2
514
515static int
516iface_ChangeFlags(const char *ifname, int flags, int how)
517{

--- 50 unchanged lines hidden (view full) ---

568 /*
569 * iface_Clear(iface, IFACE_CLEAR_ALL) must be called manually
570 * if that's what the user wants. It's better to leave the interface
571 * allocated so that existing connections can continue to work.
572 */
573
574 if (iface != NULL) {
575 free(iface->name);
576 free(iface->addr);
577 free(iface);
578 }
579}
580
581#define if_entry(x) { IFF_##x, #x }
582
583struct {
584 int flag;

--- 15 unchanged lines hidden (view full) ---

600 if_entry(LINK2),
601 if_entry(MULTICAST),
602 { 0, "???" }
603};
604
605int
606iface_Show(struct cmdargs const *arg)
607{
608 struct ncpaddr ncpaddr;
609 struct iface *iface = arg->bundle->iface, *current;
610 int f, flags;
611#ifndef NOINET6
612 int scopeid, width;
613#endif
614 struct in_addr mask;
615
616 current = iface_Create(iface->name);
617 flags = iface->flags = current->flags;
618 iface_Destroy(current);
619
620 prompt_Printf(arg->prompt, "%s (idx %d) <", iface->name, iface->index);
621 for (f = 0; f < sizeof if_flags / sizeof if_flags[0]; f++)
622 if ((if_flags[f].flag & flags) || (!if_flags[f].flag && flags)) {
623 prompt_Printf(arg->prompt, "%s%s", flags == iface->flags ? "" : ",",
624 if_flags[f].value);
625 flags &= ~if_flags[f].flag;
626 }
627 prompt_Printf(arg->prompt, "> mtu %d has %d address%s:\n", iface->mtu,
628 iface->addrs, iface->addrs == 1 ? "" : "es");
629
630 for (f = 0; f < iface->addrs; f++) {
631 ncprange_getaddr(&iface->addr[f].ifa, &ncpaddr);
632 switch (ncprange_family(&iface->addr[f].ifa)) {
633 case AF_INET:
634 prompt_Printf(arg->prompt, " inet %s --> ", ncpaddr_ntoa(&ncpaddr));
635 if (ncpaddr_family(&iface->addr[f].peer) == AF_UNSPEC)
636 prompt_Printf(arg->prompt, "255.255.255.255");
637 else
638 prompt_Printf(arg->prompt, "%s", ncpaddr_ntoa(&iface->addr[f].peer));
639 ncprange_getip4mask(&iface->addr[f].ifa, &mask);
640 prompt_Printf(arg->prompt, " netmask 0x%08lx", (long)ntohl(mask.s_addr));
641 break;
642
643#ifndef NOINET6
644 case AF_INET6:
645 prompt_Printf(arg->prompt, " inet6 %s", ncpaddr_ntoa(&ncpaddr));
646 if (ncpaddr_family(&iface->addr[f].peer) != AF_UNSPEC)
647 prompt_Printf(arg->prompt, " --> %s",
648 ncpaddr_ntoa(&iface->addr[f].peer));
649 ncprange_getwidth(&iface->addr[f].ifa, &width);
650 prompt_Printf(arg->prompt, " prefixlen %d", width);
651 if ((scopeid = ncprange_scopeid(&iface->addr[f].ifa)) != -1)
652 prompt_Printf(arg->prompt, " scopeid 0x%x", (unsigned)scopeid);
653 break;
654#endif
655 }
656 prompt_Printf(arg->prompt, "\n");
657 }
658
659 return 0;
660}
661
662void
663iface_ParseHdr(struct ifa_msghdr *ifam, struct sockaddr *sa[RTAX_MAX])

--- 13 unchanged lines hidden ---