46#include <termios.h> 47#include <unistd.h> 48 49#include "defs.h" 50#include "command.h" 51#include "mbuf.h" 52#include "log.h" 53#include "id.h" 54#include "timer.h" 55#include "fsm.h" 56#include "iplist.h" 57#include "lqr.h" 58#include "hdlc.h" 59#include "throughput.h" 60#include "slcompress.h" 61#include "filter.h" 62#include "descriptor.h" 63#include "ipcp.h" 64#include "lcp.h" 65#include "ccp.h" 66#include "link.h" 67#include "mp.h" 68#ifndef NORADIUS 69#include "radius.h" 70#endif 71#include "bundle.h" 72#include "prompt.h" 73#include "iface.h" 74 75 76static int 77bitsinmask(struct in_addr mask) 78{ 79 u_int32_t bitmask, maskaddr; 80 int bits; 81 82 bitmask = 0xffffffff; 83 maskaddr = ntohl(mask.s_addr); 84 for (bits = 32; bits >= 0; bits--) { 85 if (maskaddr == bitmask) 86 break; 87 bitmask &= ~(1 << (32 - bits)); 88 } 89 90 return bits; 91} 92 93struct iface * 94iface_Create(const char *name) 95{ 96 int mib[6], i, s; 97 size_t needed; 98 char *buf, *ptr, *end, *cp, *lim; 99 struct if_msghdr *ifm; 100 struct ifa_msghdr *ifam; 101 struct sockaddr_dl *dl; 102 struct rt_addrinfo rti; 103 struct iface *iface; 104 struct iface_addr *addr; 105 106 s = socket(AF_INET, SOCK_DGRAM, 0); 107 if (s < 0) { 108 fprintf(stderr, "iface_Create: socket(): %s\n", strerror(errno)); 109 return NULL; 110 } 111 112 mib[0] = CTL_NET; 113 mib[1] = PF_ROUTE; 114 mib[2] = 0; 115 mib[3] = 0; 116 mib[4] = NET_RT_IFLIST; 117 mib[5] = 0; 118 119 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 120 fprintf(stderr, "clean: sysctl: estimate: %s\n", 121 strerror(errno)); 122 close(s); 123 return NULL; 124 } 125 126 if ((buf = (char *)malloc(needed)) == NULL) { 127 close(s); 128 return NULL; 129 } 130 131 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { 132 free(buf); 133 close(s); 134 return NULL; 135 } 136 137 ptr = buf; 138 end = buf + needed; 139 iface = NULL; 140 141 while (ptr < end && iface == NULL) { 142 ifm = (struct if_msghdr *)ptr; /* On if_msghdr */ 143 if (ifm->ifm_type != RTM_IFINFO) 144 break; 145 dl = (struct sockaddr_dl *)(ifm + 1); /* Single _dl at end */ 146 if (!strncmp(name, dl->sdl_data, dl->sdl_nlen)) { 147 iface = (struct iface *)malloc(sizeof *iface); 148 if (iface == NULL) { 149 fprintf(stderr, "iface_Create: malloc: %s\n", strerror(errno)); 150 return NULL; 151 } 152 iface->name = strdup(name); 153 iface->flags = ifm->ifm_flags; 154 iface->index = ifm->ifm_index; 155 iface->in_addrs = 0; 156 iface->in_addr = NULL; 157 } 158 ptr += ifm->ifm_msglen; /* First ifa_msghdr */ 159 for (; ptr < end; ptr += ifam->ifam_msglen) { 160 ifam = (struct ifa_msghdr *)ptr; /* Next if address */ 161 162 if (ifam->ifam_type != RTM_NEWADDR) /* finished this if */ 163 break; 164 165 if (iface == NULL) /* Keep wading */ 166 continue; 167 168 /* Found an address ! */ 169 170 if (ifam->ifam_addrs & (1 << RTAX_IFA)) { 171 /* *And* it's configured ! */ 172 rti.rti_addrs = ifam->ifam_addrs; 173 lim = (char *)ifam + ifam->ifam_msglen; 174 cp = (char *)(ifam + 1); 175 memset(rti.rti_info, '\0', sizeof(rti.rti_info)); 176 for (i = 0; i < RTAX_MAX && cp < lim; i++) { 177 if ((rti.rti_addrs & (1 << i)) == 0) 178 continue; 179 rti.rti_info[i] = (struct sockaddr *)cp; 180#define ROUNDUP(x) \ 181 ((x) > 0 ? (1 + (((x) - 1) | (sizeof(long) - 1))) : sizeof(long)) 182 cp += ROUNDUP(rti.rti_info[i]->sa_len); 183 } 184 185 if (rti.rti_info[RTAX_IFA] && 186 rti.rti_info[RTAX_IFA]->sa_family == AF_INET) { 187 /* Record the iface address rti */ 188 189 addr = (struct iface_addr *)realloc 190 (iface->in_addr, (iface->in_addrs + 1) * sizeof iface->in_addr[0]); 191 if (addr == NULL) 192 break; 193 iface->in_addr = addr; 194 195 addr += iface->in_addrs; 196 iface->in_addrs++; 197 198 addr->ifa.s_addr = ((struct sockaddr_in *)rti.rti_info[RTAX_IFA])-> 199 sin_addr.s_addr; 200 addr->brd.s_addr = rti.rti_info[RTAX_BRD] ? 201 ((struct sockaddr_in *)rti.rti_info[RTAX_BRD])->sin_addr.s_addr : 202 INADDR_ANY; 203 addr->mask.s_addr = rti.rti_info[RTAX_NETMASK] ? 204 ((struct sockaddr_in *)rti.rti_info[RTAX_NETMASK])->sin_addr.s_addr: 205 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 addrs = n = how == IFACE_CLEAR_ALL ? 0 : 1; 252 for (; n < iface->in_addrs; n++) 253 iface_addr_Zap(iface->name, iface->in_addr + n); 254 255 iface->in_addrs = addrs; 256 /* Don't bother realloc()ing - we have little to gain */ 257} 258 259int 260iface_inAdd(struct iface *iface, struct in_addr ifa, struct in_addr mask, 261 struct in_addr brd, int how) 262{ 263 int slot, s, chg; 264 struct ifaliasreq ifra; 265 struct sockaddr_in *me, *peer, *msk; 266 struct iface_addr *addr; 267 268 for (slot = 0; slot < iface->in_addrs; slot++) 269 if (iface->in_addr[slot].ifa.s_addr == ifa.s_addr) { 270 if (how & IFACE_FORCE_ADD) 271 break; 272 else 273 /* errno = EEXIST; */ 274 return 0; 275 } 276 277 addr = (struct iface_addr *)realloc 278 (iface->in_addr, (iface->in_addrs + 1) * sizeof iface->in_addr[0]); 279 if (addr == NULL) { 280 log_Printf(LogERROR, "iface_inAdd: realloc: %s\n", strerror(errno)); 281 return 0; 282 } 283 iface->in_addr = addr; 284 285 s = ID0socket(AF_INET, SOCK_DGRAM, 0); 286 if (s < 0) { 287 log_Printf(LogERROR, "iface_inAdd: socket(): %s\n", strerror(errno)); 288 return 0; 289 } 290 291 /* 292 * We've gotta be careful here. If we try to add an address with the 293 * same destination as an existing interface, nothing will work. 294 * Instead, we tweak all previous address entries that match the 295 * to-be-added destination to 255.255.255.255 (w/ a similar netmask). 296 * There *may* be more than one - if the user has ``iface add''ed 297 * stuff previously. 298 */ 299 for (chg = 0; chg < iface->in_addrs; chg++) { 300 if ((iface->in_addr[chg].brd.s_addr == brd.s_addr && 301 brd.s_addr != INADDR_BROADCAST) || chg == slot) { 302 memset(&ifra, '\0', sizeof ifra); 303 strncpy(ifra.ifra_name, iface->name, sizeof ifra.ifra_name - 1); 304 me = (struct sockaddr_in *)&ifra.ifra_addr; 305 msk = (struct sockaddr_in *)&ifra.ifra_mask; 306 peer = (struct sockaddr_in *)&ifra.ifra_broadaddr; 307 me->sin_family = msk->sin_family = peer->sin_family = AF_INET; 308 me->sin_len = msk->sin_len = peer->sin_len = sizeof(struct sockaddr_in); 309 me->sin_addr = iface->in_addr[chg].ifa; 310 msk->sin_addr = iface->in_addr[chg].mask; 311 peer->sin_addr = iface->in_addr[chg].brd; 312 log_Printf(LogDEBUG, "Delete %s\n", inet_ntoa(me->sin_addr)); 313 ID0ioctl(s, SIOCDIFADDR, &ifra); /* Don't care if it fails... */ 314 if (chg != slot) { 315 peer->sin_addr.s_addr = iface->in_addr[chg].brd.s_addr = 316 msk->sin_addr.s_addr = iface->in_addr[chg].mask.s_addr = 317 INADDR_BROADCAST; 318 iface->in_addr[chg].bits = 32; 319 log_Printf(LogDEBUG, "Add %s -> 255.255.255.255\n", 320 inet_ntoa(me->sin_addr)); 321 if (ID0ioctl(s, SIOCAIFADDR, &ifra) < 0 && errno != EEXIST) { 322 /* Oops - that's bad(ish) news ! We've lost an alias ! */ 323 log_Printf(LogERROR, "iface_inAdd: ioctl(SIOCAIFADDR): %s: %s\n", 324 inet_ntoa(me->sin_addr), strerror(errno)); 325 iface->in_addrs--; 326 bcopy(iface->in_addr + chg + 1, iface->in_addr + chg, 327 (iface->in_addrs - chg) * sizeof iface->in_addr[0]); 328 if (slot > chg) 329 slot--; 330 chg--; 331 } 332 } 333 } 334 } 335 336 memset(&ifra, '\0', sizeof ifra); 337 strncpy(ifra.ifra_name, iface->name, sizeof ifra.ifra_name - 1); 338 me = (struct sockaddr_in *)&ifra.ifra_addr; 339 msk = (struct sockaddr_in *)&ifra.ifra_mask; 340 peer = (struct sockaddr_in *)&ifra.ifra_broadaddr; 341 me->sin_family = msk->sin_family = peer->sin_family = AF_INET; 342 me->sin_len = msk->sin_len = peer->sin_len = sizeof(struct sockaddr_in); 343 me->sin_addr = ifa; 344 msk->sin_addr = mask; 345 peer->sin_addr = brd; 346 347 if (log_IsKept(LogDEBUG)) { 348 char buf[16]; 349 350 strncpy(buf, inet_ntoa(brd), sizeof buf-1); 351 buf[sizeof buf - 1] = '\0'; 352 log_Printf(LogDEBUG, "Add %s -> %s\n", inet_ntoa(ifa), buf); 353 } 354 355 /* An EEXIST failure w/ brd == INADDR_BROADCAST is ok (and works!) */ 356 if (ID0ioctl(s, SIOCAIFADDR, &ifra) < 0 && 357 (brd.s_addr != INADDR_BROADCAST || errno != EEXIST)) { 358 log_Printf(LogERROR, "iface_inAdd: ioctl(SIOCAIFADDR): %s: %s\n", 359 inet_ntoa(ifa), strerror(errno)); 360 ID0ioctl(s, SIOCDIFADDR, &ifra); /* EEXIST ? */ 361 close(s); 362 return 0; 363 } 364 close(s); 365 366 if (slot == iface->in_addrs) { 367 /* We're adding a new interface address */ 368 369 if (how & IFACE_ADD_FIRST) { 370 /* Stuff it at the start of our list */ 371 slot = 0; 372 bcopy(iface->in_addr, iface->in_addr + 1, 373 iface->in_addrs * sizeof iface->in_addr[0]); 374 } 375 376 iface->in_addrs++; 377 } else if (how & IFACE_ADD_FIRST) { 378 /* Shift it up to the first slot */ 379 bcopy(iface->in_addr, iface->in_addr + 1, slot * sizeof iface->in_addr[0]); 380 slot = 0; 381 } 382 383 iface->in_addr[slot].ifa = ifa; 384 iface->in_addr[slot].mask = mask; 385 iface->in_addr[slot].brd = brd; 386 iface->in_addr[slot].bits = bitsinmask(iface->in_addr[slot].mask); 387 388 return 1; 389} 390 391int 392iface_inDelete(struct iface *iface, struct in_addr ip) 393{ 394 int n; 395 396 for (n = 0; n < iface->in_addrs; n++) 397 if (iface->in_addr[n].ifa.s_addr == ip.s_addr) { 398 iface_addr_Zap(iface->name, iface->in_addr + n); 399 bcopy(iface->in_addr + n + 1, iface->in_addr + n, 400 (iface->in_addrs - n - 1) * sizeof iface->in_addr[0]); 401 iface->in_addrs--; 402 return 1; 403 } 404 405 return 0; 406} 407 408void 409iface_Destroy(struct iface *iface) 410{ 411 /* 412 * iface_Clear(iface, IFACE_CLEAR_ALL) must be called manually 413 * if that's what the user wants. It's better to leave the interface 414 * allocated so that existing connections can continue to work. 415 */ 416 417 if (iface != NULL) { 418 free(iface->name); 419 free(iface->in_addr); 420 free(iface); 421 } 422} 423 424#define if_entry(x) { IFF_##x, #x } 425 426struct { 427 int flag; 428 const char *value; 429} if_flags[] = { 430 if_entry(UP), 431 if_entry(BROADCAST), 432 if_entry(DEBUG), 433 if_entry(LOOPBACK), 434 if_entry(POINTOPOINT), 435 if_entry(RUNNING), 436 if_entry(NOARP), 437 if_entry(PROMISC), 438 if_entry(ALLMULTI), 439 if_entry(OACTIVE), 440 if_entry(SIMPLEX), 441 if_entry(LINK0), 442 if_entry(LINK1), 443 if_entry(LINK2), 444 if_entry(MULTICAST), 445 { 0, "???" } 446}; 447 448int 449iface_Show(struct cmdargs const *arg) 450{ 451 struct iface *iface = arg->bundle->iface, *current; 452 int f, flags; 453 454 current = iface_Create(iface->name); 455 flags = iface->flags = current->flags; 456 iface_Destroy(current); 457 458 prompt_Printf(arg->prompt, "%s (idx %d) <", iface->name, iface->index); 459 for (f = 0; f < sizeof if_flags / sizeof if_flags[0]; f++) 460 if ((if_flags[f].flag & flags) || (!if_flags[f].flag && flags)) { 461 prompt_Printf(arg->prompt, "%s%s", flags == iface->flags ? "" : ",", 462 if_flags[f].value); 463 flags &= ~if_flags[f].flag; 464 } 465 prompt_Printf(arg->prompt, "> has %d address%s:\n", iface->in_addrs, 466 iface->in_addrs == 1 ? "" : "es"); 467 468 for (f = 0; f < iface->in_addrs; f++) { 469 prompt_Printf(arg->prompt, " %s", inet_ntoa(iface->in_addr[f].ifa)); 470 if (iface->in_addr[f].bits >= 0) 471 prompt_Printf(arg->prompt, "/%d", iface->in_addr[f].bits); 472 if (iface->flags & IFF_POINTOPOINT) 473 prompt_Printf(arg->prompt, " -> %s", inet_ntoa(iface->in_addr[f].brd)); 474 else if (iface->flags & IFF_BROADCAST) 475 prompt_Printf(arg->prompt, " broadcast %s", 476 inet_ntoa(iface->in_addr[f].brd)); 477 if (iface->in_addr[f].bits < 0) 478 prompt_Printf(arg->prompt, " (mask %s)", 479 inet_ntoa(iface->in_addr[f].mask)); 480 prompt_Printf(arg->prompt, "\n"); 481 } 482 483 return 0; 484}
|