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 78410 2001-06-18 14:59:36Z 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/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>

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

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
77static int
78bitsinmask(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
94struct iface *
95iface_Create(const char *name)
96{
97 int mib[6], s, maxtries, err;
98 size_t needed, namelen;
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 maxtries = 20;
121 err = 0;
122 do {
123 if (maxtries-- == 0 || (err && err != ENOMEM)) {
124 fprintf(stderr, "iface_Create: sysctl: %s\n", strerror(err));
125 close(s);
126 return NULL;
127 }
128
129 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
130 fprintf(stderr, "iface_Create: sysctl: estimate: %s\n",
131 strerror(errno));
132 close(s);
133 return NULL;
134 }
135
136 if ((buf = (char *)malloc(needed)) == NULL) {
137 fprintf(stderr, "iface_Create: malloc failed: %s\n", strerror(errno));
138 close(s);
139 return NULL;
140 }
141
142 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
143 err = errno;
144 free(buf);
145 buf = NULL;
146 }

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

161 if (iface == NULL) {
162 fprintf(stderr, "iface_Create: malloc: %s\n", strerror(errno));
163 return NULL;
164 }
165 iface->name = strdup(name);
166 iface->index = ifm->ifm_index;
167 iface->flags = ifm->ifm_flags;
168 iface->mtu = 0;
169 iface->in_addrs = 0;
170 iface->in_addr = NULL;
171 }
172 ptr += ifm->ifm_msglen; /* First ifa_msghdr */
173 for (; ptr < end; ptr += ifam->ifam_msglen) {
174 ifam = (struct ifa_msghdr *)ptr; /* Next if address */
175
176 if (ifam->ifam_type != RTM_NEWADDR) /* finished this if */
177 break;
178
179 if (iface != NULL && ifam->ifam_addrs & RTA_IFA) {
180 /* Found a configured interface ! */
181 iface_ParseHdr(ifam, sa);
182
183 if (sa[RTAX_IFA] && sa[RTAX_IFA]->sa_family == AF_INET) {
184 /* Record the address */
185
186 addr = (struct iface_addr *)realloc
187 (iface->in_addr, (iface->in_addrs + 1) * sizeof iface->in_addr[0]);
188 if (addr == NULL)
189 break;
190 iface->in_addr = addr;
191
192 addr += iface->in_addrs;
193 iface->in_addrs++;
194
195 addr->ifa = ((struct sockaddr_in *)sa[RTAX_IFA])->sin_addr;
196
197 if (sa[RTAX_BRD])
198 addr->brd = ((struct sockaddr_in *)sa[RTAX_BRD])->sin_addr;
199 else
200 addr->brd.s_addr = INADDR_ANY;
201
202 if (sa[RTAX_NETMASK])
203 addr->mask = ((struct sockaddr_in *)sa[RTAX_NETMASK])->sin_addr;
204 else
205 addr->mask.s_addr = INADDR_ANY;
206
207 addr->bits = bitsinmask(addr->mask);
208 }
209 }
210 }
211 }
212
213 free(buf);
214 close(s);
215
216 return iface;
217}
218
219static void
220iface_addr_Zap(const char *name, struct iface_addr *addr)
221{
222 struct ifaliasreq ifra;
223 struct sockaddr_in *me, *peer;
224 int s;
225
226 s = ID0socket(AF_INET, SOCK_DGRAM, 0);
227 if (s < 0)
228 log_Printf(LogERROR, "iface_addr_Zap: socket(): %s\n", strerror(errno));
229 else {
230 memset(&ifra, '\0', sizeof ifra);
231 strncpy(ifra.ifra_name, name, sizeof ifra.ifra_name - 1);
232 me = (struct sockaddr_in *)&ifra.ifra_addr;
233 peer = (struct sockaddr_in *)&ifra.ifra_broadaddr;
234 me->sin_family = peer->sin_family = AF_INET;
235 me->sin_len = peer->sin_len = sizeof(struct sockaddr_in);
236 me->sin_addr = addr->ifa;
237 peer->sin_addr = addr->brd;
238 log_Printf(LogDEBUG, "Delete %s\n", inet_ntoa(addr->ifa));
239 if (ID0ioctl(s, SIOCDIFADDR, &ifra) < 0)
240 log_Printf(LogWARN, "iface_addr_Zap: ioctl(SIOCDIFADDR, %s): %s\n",
241 inet_ntoa(addr->ifa), strerror(errno));
242 close(s);
243 }
244}
245
246void
247iface_inClear(struct iface *iface, int how)
248{
249 int n, addrs;
250
251 if (iface->in_addrs) {
252 addrs = n = how == IFACE_CLEAR_ALL ? 0 : 1;
253 for (; n < iface->in_addrs; n++)
254 iface_addr_Zap(iface->name, iface->in_addr + n);
255
256 iface->in_addrs = addrs;
257 /* Don't bother realloc()ing - we have little to gain */
258 }
259}
260
261int
262iface_inAdd(struct iface *iface, struct in_addr ifa, struct in_addr mask,
263 struct in_addr brd, int how)
264{
265 int slot, s, chg, nochange;
266 struct ifaliasreq ifra;
267 struct sockaddr_in *me, *peer, *msk;
268 struct iface_addr *addr;
269
270 for (slot = 0; slot < iface->in_addrs; slot++)
271 if (iface->in_addr[slot].ifa.s_addr == ifa.s_addr) {
272 if (how & IFACE_FORCE_ADD)
273 break;
274 else
275 /* errno = EEXIST; */
276 return 0;
277 }
278
279 addr = (struct iface_addr *)realloc
280 (iface->in_addr, (iface->in_addrs + 1) * sizeof iface->in_addr[0]);
281 if (addr == NULL) {
282 log_Printf(LogERROR, "iface_inAdd: realloc: %s\n", strerror(errno));
283 return 0;
284 }
285 iface->in_addr = addr;
286
287 /*
288 * We've gotta be careful here. If we try to add an address with the
289 * same destination as an existing interface, nothing will work.
290 * Instead, we tweak all previous address entries that match the
291 * to-be-added destination to 255.255.255.255 (w/ a similar netmask).
292 * There *may* be more than one - if the user has ``iface add''ed
293 * stuff previously.
294 */
295 nochange = 0;
296 s = -1;
297 for (chg = 0; chg < iface->in_addrs; chg++) {
298 if ((iface->in_addr[chg].brd.s_addr == brd.s_addr &&
299 brd.s_addr != INADDR_BROADCAST) || chg == slot) {
300 /*
301 * If we've found an entry that exactly matches what we want to add,
302 * don't remove it and then add it again. If we do, it's possible
303 * that the kernel will (correctly) ``tidy up'' any routes that use
304 * the IP number as a destination.
305 */
306 if (chg == slot && iface->in_addr[chg].mask.s_addr == mask.s_addr) {
307 if (brd.s_addr == iface->in_addr[slot].brd.s_addr)
308 nochange = 1;
309 /*
310 * If only the destination address has changed, the SIOCAIFADDR
311 * we do after the current loop will change it.
312 */
313 continue;
314 }
315 if (s == -1 && (s = ID0socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
316 log_Printf(LogERROR, "iface_inAdd: socket(): %s\n", strerror(errno));
317 return 0;
318 }
319
320 memset(&ifra, '\0', sizeof ifra);
321 strncpy(ifra.ifra_name, iface->name, sizeof ifra.ifra_name - 1);
322 me = (struct sockaddr_in *)&ifra.ifra_addr;
323 msk = (struct sockaddr_in *)&ifra.ifra_mask;
324 peer = (struct sockaddr_in *)&ifra.ifra_broadaddr;
325 me->sin_family = msk->sin_family = peer->sin_family = AF_INET;
326 me->sin_len = msk->sin_len = peer->sin_len = sizeof(struct sockaddr_in);
327 me->sin_addr = iface->in_addr[chg].ifa;
328 msk->sin_addr = iface->in_addr[chg].mask;
329 peer->sin_addr = iface->in_addr[chg].brd;
330 log_Printf(LogDEBUG, "Delete %s\n", inet_ntoa(me->sin_addr));
331 ID0ioctl(s, SIOCDIFADDR, &ifra); /* Don't care if it fails... */
332 if (chg != slot) {
333 peer->sin_addr.s_addr = iface->in_addr[chg].brd.s_addr =
334 msk->sin_addr.s_addr = iface->in_addr[chg].mask.s_addr =
335 INADDR_BROADCAST;
336 iface->in_addr[chg].bits = 32;
337 log_Printf(LogDEBUG, "Add %s -> 255.255.255.255\n",
338 inet_ntoa(me->sin_addr));
339 if (ID0ioctl(s, SIOCAIFADDR, &ifra) < 0 && errno != EEXIST) {
340 /* Oops - that's bad(ish) news ! We've lost an alias ! */
341 log_Printf(LogERROR, "iface_inAdd: ioctl(SIOCAIFADDR): %s: %s\n",
342 inet_ntoa(me->sin_addr), strerror(errno));
343 iface->in_addrs--;
344 bcopy(iface->in_addr + chg + 1, iface->in_addr + chg,
345 (iface->in_addrs - chg) * sizeof iface->in_addr[0]);
346 if (slot > chg)
347 slot--;
348 chg--;
349 }
350 }
351 }
352 }
353
354 if (!nochange) {
355 if (s == -1 && (s = ID0socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
356 log_Printf(LogERROR, "iface_inAdd: socket(): %s\n", strerror(errno));
357 return 0;
358 }
359 memset(&ifra, '\0', sizeof ifra);
360 strncpy(ifra.ifra_name, iface->name, sizeof ifra.ifra_name - 1);
361 me = (struct sockaddr_in *)&ifra.ifra_addr;
362 msk = (struct sockaddr_in *)&ifra.ifra_mask;
363 peer = (struct sockaddr_in *)&ifra.ifra_broadaddr;
364 me->sin_family = msk->sin_family = peer->sin_family = AF_INET;
365 me->sin_len = msk->sin_len = peer->sin_len = sizeof(struct sockaddr_in);
366 me->sin_addr = ifa;
367 msk->sin_addr = mask;
368 peer->sin_addr = brd;
369
370 if (log_IsKept(LogDEBUG)) {
371 char buf[16];
372
373 strncpy(buf, inet_ntoa(brd), sizeof buf-1);
374 buf[sizeof buf - 1] = '\0';
375 log_Printf(LogDEBUG, "Add %s -> %s\n", inet_ntoa(ifa), buf);
376 }
377
378 /* An EEXIST failure w/ brd == INADDR_BROADCAST is ok (and works!) */
379 if (ID0ioctl(s, SIOCAIFADDR, &ifra) < 0 &&
380 (brd.s_addr != INADDR_BROADCAST || errno != EEXIST)) {
381 log_Printf(LogERROR, "iface_inAdd: ioctl(SIOCAIFADDR): %s: %s\n",
382 inet_ntoa(ifa), strerror(errno));
383 ID0ioctl(s, SIOCDIFADDR, &ifra); /* EEXIST ? */
384 close(s);
385 return 0;
386 }
387 }
388
389 if (s != -1)
390 close(s);
391
392 if (slot == iface->in_addrs) {
393 /* We're adding a new interface address */
394
395 if (how & IFACE_ADD_FIRST) {
396 /* Stuff it at the start of our list */
397 slot = 0;
398 bcopy(iface->in_addr, iface->in_addr + 1,
399 iface->in_addrs * sizeof iface->in_addr[0]);
400 }
401
402 iface->in_addrs++;
403 } else if (how & IFACE_ADD_FIRST) {
404 /* Shift it up to the first slot */
405 bcopy(iface->in_addr, iface->in_addr + 1, slot * sizeof iface->in_addr[0]);
406 slot = 0;
407 }
408
409 iface->in_addr[slot].ifa = ifa;
410 iface->in_addr[slot].mask = mask;
411 iface->in_addr[slot].brd = brd;
412 iface->in_addr[slot].bits = bitsinmask(iface->in_addr[slot].mask);
413
414 return 1;
415}
416
417int
418iface_inDelete(struct iface *iface, struct in_addr ip)
419{
420 int n;
421
422 for (n = 0; n < iface->in_addrs; n++)
423 if (iface->in_addr[n].ifa.s_addr == ip.s_addr) {
424 iface_addr_Zap(iface->name, iface->in_addr + n);
425 bcopy(iface->in_addr + n + 1, iface->in_addr + n,
426 (iface->in_addrs - n - 1) * sizeof iface->in_addr[0]);
427 iface->in_addrs--;
428 return 1;
429 }
430
431 return 0;
432}
433
434#define IFACE_ADDFLAGS 1
435#define IFACE_DELFLAGS 2
436
437static int
438iface_ChangeFlags(const char *ifname, int flags, int how)
439{

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

490 /*
491 * iface_Clear(iface, IFACE_CLEAR_ALL) must be called manually
492 * if that's what the user wants. It's better to leave the interface
493 * allocated so that existing connections can continue to work.
494 */
495
496 if (iface != NULL) {
497 free(iface->name);
498 free(iface->in_addr);
499 free(iface);
500 }
501}
502
503#define if_entry(x) { IFF_##x, #x }
504
505struct {
506 int flag;

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

522 if_entry(LINK2),
523 if_entry(MULTICAST),
524 { 0, "???" }
525};
526
527int
528iface_Show(struct cmdargs const *arg)
529{
530 struct iface *iface = arg->bundle->iface, *current;
531 int f, flags;
532
533 current = iface_Create(iface->name);
534 flags = iface->flags = current->flags;
535 iface_Destroy(current);
536
537 prompt_Printf(arg->prompt, "%s (idx %d) <", iface->name, iface->index);
538 for (f = 0; f < sizeof if_flags / sizeof if_flags[0]; f++)
539 if ((if_flags[f].flag & flags) || (!if_flags[f].flag && flags)) {
540 prompt_Printf(arg->prompt, "%s%s", flags == iface->flags ? "" : ",",
541 if_flags[f].value);
542 flags &= ~if_flags[f].flag;
543 }
544 prompt_Printf(arg->prompt, "> mtu %d has %d address%s:\n", iface->mtu,
545 iface->in_addrs, iface->in_addrs == 1 ? "" : "es");
546
547 for (f = 0; f < iface->in_addrs; f++) {
548 prompt_Printf(arg->prompt, " %s", inet_ntoa(iface->in_addr[f].ifa));
549 if (iface->in_addr[f].bits >= 0)
550 prompt_Printf(arg->prompt, "/%d", iface->in_addr[f].bits);
551 if (iface->flags & IFF_POINTOPOINT)
552 prompt_Printf(arg->prompt, " -> %s", inet_ntoa(iface->in_addr[f].brd));
553 else if (iface->flags & IFF_BROADCAST)
554 prompt_Printf(arg->prompt, " broadcast %s",
555 inet_ntoa(iface->in_addr[f].brd));
556 if (iface->in_addr[f].bits < 0)
557 prompt_Printf(arg->prompt, " (mask %s)",
558 inet_ntoa(iface->in_addr[f].mask));
559 prompt_Printf(arg->prompt, "\n");
560 }
561
562 return 0;
563}
564
565void
566iface_ParseHdr(struct ifa_msghdr *ifam, struct sockaddr *sa[RTAX_MAX])

--- 13 unchanged lines hidden ---