xref: /freebsd/usr.sbin/ppp/iface.c (revision 56ca39961bd1c9946a505c41c3fc634ef63fdd42)
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  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
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$
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/route.h>
35 #include <arpa/inet.h>
36 #include <netinet/in_systm.h>
37 #include <netinet/ip.h>
38 #include <sys/un.h>
39 
40 #include <errno.h>
41 #include <string.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <sys/ioctl.h>
45 #include <sys/sysctl.h>
46 #include <termios.h>
47 #include <unistd.h>
48 
49 #include "layer.h"
50 #include "defs.h"
51 #include "command.h"
52 #include "mbuf.h"
53 #include "log.h"
54 #include "id.h"
55 #include "timer.h"
56 #include "fsm.h"
57 #include "iplist.h"
58 #include "lqr.h"
59 #include "hdlc.h"
60 #include "throughput.h"
61 #include "slcompress.h"
62 #include "descriptor.h"
63 #include "ipcp.h"
64 #include "filter.h"
65 #include "lcp.h"
66 #include "ccp.h"
67 #include "link.h"
68 #include "mp.h"
69 #ifndef NORADIUS
70 #include "radius.h"
71 #endif
72 #include "bundle.h"
73 #include "prompt.h"
74 #include "iface.h"
75 
76 
77 static int
78 bitsinmask(struct in_addr mask)
79 {
80   u_int32_t bitmask, maskaddr;
81   int bits;
82 
83   bitmask = 0xffffffff;
84   maskaddr = ntohl(mask.s_addr);
85   for (bits = 32; bits >= 0; bits--) {
86     if (maskaddr == bitmask)
87       break;
88     bitmask &= ~(1 << (32 - bits));
89   }
90 
91   return bits;
92 }
93 
94 struct iface *
95 iface_Create(const char *name)
96 {
97   int mib[6], s;
98   size_t needed;
99   char *buf, *ptr, *end;
100   struct if_msghdr *ifm;
101   struct ifa_msghdr *ifam;
102   struct sockaddr_dl *dl;
103   struct sockaddr *sa[RTAX_MAX];
104   struct iface *iface;
105   struct iface_addr *addr;
106 
107   s = socket(AF_INET, SOCK_DGRAM, 0);
108   if (s < 0) {
109     fprintf(stderr, "iface_Create: socket(): %s\n", strerror(errno));
110     return NULL;
111   }
112 
113   mib[0] = CTL_NET;
114   mib[1] = PF_ROUTE;
115   mib[2] = 0;
116   mib[3] = 0;
117   mib[4] = NET_RT_IFLIST;
118   mib[5] = 0;
119 
120   if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
121     fprintf(stderr, "iface_Create: sysctl: estimate: %s\n",
122               strerror(errno));
123     close(s);
124     return NULL;
125   }
126 
127   if ((buf = (char *)malloc(needed)) == NULL) {
128     fprintf(stderr, "iface_Create: malloc failed: %s\n", strerror(errno));
129     close(s);
130     return NULL;
131   }
132 
133   if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
134     fprintf(stderr, "iface_Create: sysctl: %s\n", strerror(errno));
135     free(buf);
136     close(s);
137     return NULL;
138   }
139 
140   ptr = buf;
141   end = buf + needed;
142   iface = NULL;
143 
144   while (ptr < end && iface == NULL) {
145     ifm = (struct if_msghdr *)ptr;			/* On if_msghdr */
146     if (ifm->ifm_type != RTM_IFINFO)
147       break;
148     dl = (struct sockaddr_dl *)(ifm + 1);		/* Single _dl at end */
149     if (!strncmp(name, dl->sdl_data, dl->sdl_nlen)) {
150       iface = (struct iface *)malloc(sizeof *iface);
151       if (iface == NULL) {
152         fprintf(stderr, "iface_Create: malloc: %s\n", strerror(errno));
153         return NULL;
154       }
155       iface->name = strdup(name);
156       iface->flags = ifm->ifm_flags;
157       iface->index = ifm->ifm_index;
158       iface->in_addrs = 0;
159       iface->in_addr = NULL;
160     }
161     ptr += ifm->ifm_msglen;				/* First ifa_msghdr */
162     for (; ptr < end; ptr += ifam->ifam_msglen) {
163       ifam = (struct ifa_msghdr *)ptr;			/* Next if address */
164 
165       if (ifam->ifam_type != RTM_NEWADDR)		/* finished this if */
166         break;
167 
168       if (iface != NULL && ifam->ifam_addrs & RTA_IFA) {
169         /* Found a configured interface ! */
170         iface_ParseHdr(ifam, sa);
171 
172         if (sa[RTAX_IFA] && sa[RTAX_IFA]->sa_family == AF_INET) {
173           /* Record the address */
174 
175           addr = (struct iface_addr *)realloc
176             (iface->in_addr, (iface->in_addrs + 1) * sizeof iface->in_addr[0]);
177           if (addr == NULL)
178             break;
179           iface->in_addr = addr;
180 
181           addr += iface->in_addrs;
182           iface->in_addrs++;
183 
184           addr->ifa = ((struct sockaddr_in *)sa[RTAX_IFA])->sin_addr;
185 
186           if (sa[RTAX_BRD])
187             addr->brd = ((struct sockaddr_in *)sa[RTAX_BRD])->sin_addr;
188           else
189             addr->brd.s_addr = INADDR_ANY;
190 
191           if (sa[RTAX_NETMASK])
192             addr->mask = ((struct sockaddr_in *)sa[RTAX_NETMASK])->sin_addr;
193           else
194             addr->mask.s_addr = INADDR_ANY;
195 
196           addr->bits = bitsinmask(addr->mask);
197         }
198       }
199     }
200   }
201 
202   free(buf);
203   close(s);
204 
205   return iface;
206 }
207 
208 static void
209 iface_addr_Zap(const char *name, struct iface_addr *addr)
210 {
211   struct ifaliasreq ifra;
212   struct sockaddr_in *me, *peer;
213   int s;
214 
215   s = ID0socket(AF_INET, SOCK_DGRAM, 0);
216   if (s < 0)
217     log_Printf(LogERROR, "iface_addr_Zap: socket(): %s\n", strerror(errno));
218   else {
219     memset(&ifra, '\0', sizeof ifra);
220     strncpy(ifra.ifra_name, name, sizeof ifra.ifra_name - 1);
221     me = (struct sockaddr_in *)&ifra.ifra_addr;
222     peer = (struct sockaddr_in *)&ifra.ifra_broadaddr;
223     me->sin_family = peer->sin_family = AF_INET;
224     me->sin_len = peer->sin_len = sizeof(struct sockaddr_in);
225     me->sin_addr = addr->ifa;
226     peer->sin_addr = addr->brd;
227     log_Printf(LogDEBUG, "Delete %s\n", inet_ntoa(addr->ifa));
228     if (ID0ioctl(s, SIOCDIFADDR, &ifra) < 0)
229       log_Printf(LogWARN, "iface_addr_Zap: ioctl(SIOCDIFADDR, %s): %s\n",
230                  inet_ntoa(addr->ifa), strerror(errno));
231     close(s);
232   }
233 }
234 
235 void
236 iface_inClear(struct iface *iface, int how)
237 {
238   int n, addrs;
239 
240   if (iface->in_addrs) {
241     addrs = n = how == IFACE_CLEAR_ALL ? 0 : 1;
242     for (; n < iface->in_addrs; n++)
243       iface_addr_Zap(iface->name, iface->in_addr + n);
244 
245     iface->in_addrs = addrs;
246     /* Don't bother realloc()ing - we have little to gain */
247   }
248 }
249 
250 int
251 iface_inAdd(struct iface *iface, struct in_addr ifa, struct in_addr mask,
252             struct in_addr brd, int how)
253 {
254   int slot, s, chg;
255   struct ifaliasreq ifra;
256   struct sockaddr_in *me, *peer, *msk;
257   struct iface_addr *addr;
258 
259   for (slot = 0; slot < iface->in_addrs; slot++)
260     if (iface->in_addr[slot].ifa.s_addr == ifa.s_addr) {
261       if (how & IFACE_FORCE_ADD)
262         break;
263       else
264         /* errno = EEXIST; */
265         return 0;
266     }
267 
268   addr = (struct iface_addr *)realloc
269     (iface->in_addr, (iface->in_addrs + 1) * sizeof iface->in_addr[0]);
270   if (addr == NULL) {
271     log_Printf(LogERROR, "iface_inAdd: realloc: %s\n", strerror(errno));
272     return 0;
273   }
274   iface->in_addr = addr;
275 
276   s = ID0socket(AF_INET, SOCK_DGRAM, 0);
277   if (s < 0) {
278     log_Printf(LogERROR, "iface_inAdd: socket(): %s\n", strerror(errno));
279     return 0;
280   }
281 
282   /*
283    * We've gotta be careful here.  If we try to add an address with the
284    * same destination as an existing interface, nothing will work.
285    * Instead, we tweak all previous address entries that match the
286    * to-be-added destination to 255.255.255.255 (w/ a similar netmask).
287    * There *may* be more than one - if the user has ``iface add''ed
288    * stuff previously.
289    */
290   for (chg = 0; chg < iface->in_addrs; chg++) {
291     if ((iface->in_addr[chg].brd.s_addr == brd.s_addr &&
292          brd.s_addr != INADDR_BROADCAST) || chg == slot) {
293       memset(&ifra, '\0', sizeof ifra);
294       strncpy(ifra.ifra_name, iface->name, sizeof ifra.ifra_name - 1);
295       me = (struct sockaddr_in *)&ifra.ifra_addr;
296       msk = (struct sockaddr_in *)&ifra.ifra_mask;
297       peer = (struct sockaddr_in *)&ifra.ifra_broadaddr;
298       me->sin_family = msk->sin_family = peer->sin_family = AF_INET;
299       me->sin_len = msk->sin_len = peer->sin_len = sizeof(struct sockaddr_in);
300       me->sin_addr = iface->in_addr[chg].ifa;
301       msk->sin_addr = iface->in_addr[chg].mask;
302       peer->sin_addr = iface->in_addr[chg].brd;
303       log_Printf(LogDEBUG, "Delete %s\n", inet_ntoa(me->sin_addr));
304       ID0ioctl(s, SIOCDIFADDR, &ifra);	/* Don't care if it fails... */
305       if (chg != slot) {
306         peer->sin_addr.s_addr = iface->in_addr[chg].brd.s_addr =
307           msk->sin_addr.s_addr = iface->in_addr[chg].mask.s_addr =
308             INADDR_BROADCAST;
309         iface->in_addr[chg].bits = 32;
310         log_Printf(LogDEBUG, "Add %s -> 255.255.255.255\n",
311                    inet_ntoa(me->sin_addr));
312         if (ID0ioctl(s, SIOCAIFADDR, &ifra) < 0 && errno != EEXIST) {
313           /* Oops - that's bad(ish) news !  We've lost an alias ! */
314           log_Printf(LogERROR, "iface_inAdd: ioctl(SIOCAIFADDR): %s: %s\n",
315                inet_ntoa(me->sin_addr), strerror(errno));
316           iface->in_addrs--;
317           bcopy(iface->in_addr + chg + 1, iface->in_addr + chg,
318                 (iface->in_addrs - chg) * sizeof iface->in_addr[0]);
319           if (slot > chg)
320             slot--;
321           chg--;
322         }
323       }
324     }
325   }
326 
327   memset(&ifra, '\0', sizeof ifra);
328   strncpy(ifra.ifra_name, iface->name, sizeof ifra.ifra_name - 1);
329   me = (struct sockaddr_in *)&ifra.ifra_addr;
330   msk = (struct sockaddr_in *)&ifra.ifra_mask;
331   peer = (struct sockaddr_in *)&ifra.ifra_broadaddr;
332   me->sin_family = msk->sin_family = peer->sin_family = AF_INET;
333   me->sin_len = msk->sin_len = peer->sin_len = sizeof(struct sockaddr_in);
334   me->sin_addr = ifa;
335   msk->sin_addr = mask;
336   peer->sin_addr = brd;
337 
338   if (log_IsKept(LogDEBUG)) {
339     char buf[16];
340 
341     strncpy(buf, inet_ntoa(brd), sizeof buf-1);
342     buf[sizeof buf - 1] = '\0';
343     log_Printf(LogDEBUG, "Add %s -> %s\n", inet_ntoa(ifa), buf);
344   }
345 
346   /* An EEXIST failure w/ brd == INADDR_BROADCAST is ok (and works!) */
347   if (ID0ioctl(s, SIOCAIFADDR, &ifra) < 0 &&
348       (brd.s_addr != INADDR_BROADCAST || errno != EEXIST)) {
349     log_Printf(LogERROR, "iface_inAdd: ioctl(SIOCAIFADDR): %s: %s\n",
350                inet_ntoa(ifa), strerror(errno));
351     ID0ioctl(s, SIOCDIFADDR, &ifra);	/* EEXIST ? */
352     close(s);
353     return 0;
354   }
355   close(s);
356 
357   if (slot == iface->in_addrs) {
358     /* We're adding a new interface address */
359 
360     if (how & IFACE_ADD_FIRST) {
361       /* Stuff it at the start of our list */
362       slot = 0;
363       bcopy(iface->in_addr, iface->in_addr + 1,
364             iface->in_addrs * sizeof iface->in_addr[0]);
365     }
366 
367     iface->in_addrs++;
368   } else if (how & IFACE_ADD_FIRST) {
369     /* Shift it up to the first slot */
370     bcopy(iface->in_addr, iface->in_addr + 1, slot * sizeof iface->in_addr[0]);
371     slot = 0;
372   }
373 
374   iface->in_addr[slot].ifa = ifa;
375   iface->in_addr[slot].mask = mask;
376   iface->in_addr[slot].brd = brd;
377   iface->in_addr[slot].bits = bitsinmask(iface->in_addr[slot].mask);
378 
379   return 1;
380 }
381 
382 int
383 iface_inDelete(struct iface *iface, struct in_addr ip)
384 {
385   int n;
386 
387   for (n = 0; n < iface->in_addrs; n++)
388     if (iface->in_addr[n].ifa.s_addr == ip.s_addr) {
389       iface_addr_Zap(iface->name, iface->in_addr + n);
390       bcopy(iface->in_addr + n + 1, iface->in_addr + n,
391             (iface->in_addrs - n - 1) * sizeof iface->in_addr[0]);
392       iface->in_addrs--;
393       return 1;
394     }
395 
396   return 0;
397 }
398 
399 #define IFACE_ADDFLAGS 1
400 #define IFACE_DELFLAGS 2
401 
402 static int
403 iface_ChangeFlags(struct iface *iface, int flags, int how)
404 {
405   struct ifreq ifrq;
406   int s;
407 
408   s = ID0socket(AF_INET, SOCK_DGRAM, 0);
409   if (s < 0) {
410     log_Printf(LogERROR, "iface_ChangeFlags: socket: %s\n", strerror(errno));
411     return 0;
412   }
413 
414   memset(&ifrq, '\0', sizeof ifrq);
415   strncpy(ifrq.ifr_name, iface->name, sizeof ifrq.ifr_name - 1);
416   ifrq.ifr_name[sizeof ifrq.ifr_name - 1] = '\0';
417   if (ID0ioctl(s, SIOCGIFFLAGS, &ifrq) < 0) {
418     log_Printf(LogERROR, "iface_ChangeFlags: ioctl(SIOCGIFFLAGS): %s\n",
419        strerror(errno));
420     close(s);
421     return 0;
422   }
423 
424   if (how == IFACE_ADDFLAGS)
425     ifrq.ifr_flags |= flags;
426   else
427     ifrq.ifr_flags &= ~flags;
428 
429   if (ID0ioctl(s, SIOCSIFFLAGS, &ifrq) < 0) {
430     log_Printf(LogERROR, "iface_ChangeFlags: ioctl(SIOCSIFFLAGS): %s\n",
431        strerror(errno));
432     close(s);
433     return 0;
434   }
435   close(s);
436 
437   return 1;	/* Success */
438 }
439 
440 int
441 iface_SetFlags(struct iface *iface, int flags)
442 {
443   return iface_ChangeFlags(iface, flags, IFACE_ADDFLAGS);
444 }
445 
446 int
447 iface_ClearFlags(struct iface *iface, int flags)
448 {
449   return iface_ChangeFlags(iface, flags, IFACE_DELFLAGS);
450 }
451 
452 void
453 iface_Destroy(struct iface *iface)
454 {
455   /*
456    * iface_Clear(iface, IFACE_CLEAR_ALL) must be called manually
457    * if that's what the user wants.  It's better to leave the interface
458    * allocated so that existing connections can continue to work.
459    */
460 
461   if (iface != NULL) {
462     free(iface->name);
463     free(iface->in_addr);
464     free(iface);
465   }
466 }
467 
468 #define if_entry(x) { IFF_##x, #x }
469 
470 struct {
471   int flag;
472   const char *value;
473 } if_flags[] = {
474   if_entry(UP),
475   if_entry(BROADCAST),
476   if_entry(DEBUG),
477   if_entry(LOOPBACK),
478   if_entry(POINTOPOINT),
479   if_entry(RUNNING),
480   if_entry(NOARP),
481   if_entry(PROMISC),
482   if_entry(ALLMULTI),
483   if_entry(OACTIVE),
484   if_entry(SIMPLEX),
485   if_entry(LINK0),
486   if_entry(LINK1),
487   if_entry(LINK2),
488   if_entry(MULTICAST),
489   { 0, "???" }
490 };
491 
492 int
493 iface_Show(struct cmdargs const *arg)
494 {
495   struct iface *iface = arg->bundle->iface, *current;
496   int f, flags;
497 
498   current = iface_Create(iface->name);
499   flags = iface->flags = current->flags;
500   iface_Destroy(current);
501 
502   prompt_Printf(arg->prompt, "%s (idx %d) <", iface->name, iface->index);
503   for (f = 0; f < sizeof if_flags / sizeof if_flags[0]; f++)
504     if ((if_flags[f].flag & flags) || (!if_flags[f].flag && flags)) {
505       prompt_Printf(arg->prompt, "%s%s", flags == iface->flags ? "" : ",",
506                     if_flags[f].value);
507       flags &= ~if_flags[f].flag;
508     }
509   prompt_Printf(arg->prompt, "> has %d address%s:\n", iface->in_addrs,
510                 iface->in_addrs == 1 ? "" : "es");
511 
512   for (f = 0; f < iface->in_addrs; f++) {
513     prompt_Printf(arg->prompt, "  %s", inet_ntoa(iface->in_addr[f].ifa));
514     if (iface->in_addr[f].bits >= 0)
515       prompt_Printf(arg->prompt, "/%d", iface->in_addr[f].bits);
516     if (iface->flags & IFF_POINTOPOINT)
517       prompt_Printf(arg->prompt, " -> %s", inet_ntoa(iface->in_addr[f].brd));
518     else if (iface->flags & IFF_BROADCAST)
519       prompt_Printf(arg->prompt, " broadcast %s",
520                     inet_ntoa(iface->in_addr[f].brd));
521     if (iface->in_addr[f].bits < 0)
522       prompt_Printf(arg->prompt, " (mask %s)",
523                     inet_ntoa(iface->in_addr[f].mask));
524     prompt_Printf(arg->prompt, "\n");
525   }
526 
527   return 0;
528 }
529 
530 void
531 iface_ParseHdr(struct ifa_msghdr *ifam, struct sockaddr *sa[RTAX_MAX])
532 {
533   char *wp;
534   int rtax;
535 
536   wp = (char *)(ifam + 1);
537 
538   for (rtax = 0; rtax < RTAX_MAX; rtax++)
539     if (ifam->ifam_addrs & (1 << rtax)) {
540       sa[rtax] = (struct sockaddr *)wp;
541       wp += ROUNDUP(sa[rtax]->sa_len);
542     } else
543       sa[rtax] = NULL;
544 }
545