void iface_Clear(struct iface *iface, struct ncp *ncp, int family, int how) { int addrs, af, inskip, in6skip, s4 = -1, s6 = -1, *s; unsigned n; if (iface->addrs) { inskip = in6skip = how == IFACE_CLEAR_ALL ? 0 : 1; addrs = 0; for (n = 0; n < iface->addrs; n++) { af = ncprange_family(&iface->addr[n].ifa); if (family == 0 || family == af) { if (!iface->addr[n].system && (how & IFACE_SYSTEM)) continue; switch (af) { case AF_INET: if (inskip) { inskip = 0; continue; } s = &s4; break; #ifndef NOINET6 case AF_INET6: if (in6skip) { in6skip = 0; continue; } s = &s6; break; #endif default: continue; } if (*s == -1 && (*s = ID0socket(af, SOCK_DGRAM, 0)) == -1) log_Printf(LogERROR, "iface_Clear: socket(): %s\n", strerror(errno)); else if (iface_addr_Zap(iface->name, iface->addr + n, *s)) { ncp_IfaceAddrDeleted(ncp, iface->addr + n); bcopy(iface->addr + n + 1, iface->addr + n, (iface->addrs - n - 1) * sizeof *iface->addr); iface->addrs--; n--; } } } /* Don't bother realloc()ing - we have little to gain */ if (s4) close(s4); if (s6) close(s6); } }
void ncp_IfaceAddrAdded(struct ncp *ncp, const struct iface_addr *addr) { switch (ncprange_family(&addr->ifa)) { case AF_INET: ipcp_IfaceAddrAdded(&ncp->ipcp, addr); break; #ifndef NOINET6 case AF_INET6: ipv6cp_IfaceAddrAdded(&ncp->ipv6cp, addr); break; #endif } }
int iface_Show(struct cmdargs const *arg) { struct ncpaddr ncpaddr; struct iface *iface = arg->bundle->iface, *current; unsigned f; int flags; #ifndef NOINET6 int scopeid, width; #endif struct in_addr mask; current = iface_Create(iface->name); flags = iface->flags = current->flags; iface_Free(current); prompt_Printf(arg->prompt, "%s (idx %d) <", iface->name, iface->index); for (f = 0; f < sizeof if_flags / sizeof if_flags[0]; f++) if ((if_flags[f].flag & flags)) { prompt_Printf(arg->prompt, "%s%s", flags == iface->flags ? "" : ",", if_flags[f].value); flags &= ~if_flags[f].flag; } #if 0 if (flags) prompt_Printf(arg->prompt, "%s0x%x", flags == iface->flags ? "" : ",", flags); #endif prompt_Printf(arg->prompt, "> mtu %lu has %d address%s:\n", iface->mtu, iface->addrs, iface->addrs == 1 ? "" : "es"); for (f = 0; f < iface->addrs; f++) { ncprange_getaddr(&iface->addr[f].ifa, &ncpaddr); switch (ncprange_family(&iface->addr[f].ifa)) { case AF_INET: prompt_Printf(arg->prompt, " inet %s --> ", ncpaddr_ntoa(&ncpaddr)); if (ncpaddr_family(&iface->addr[f].peer) == AF_UNSPEC) prompt_Printf(arg->prompt, "255.255.255.255"); else prompt_Printf(arg->prompt, "%s", ncpaddr_ntoa(&iface->addr[f].peer)); ncprange_getip4mask(&iface->addr[f].ifa, &mask); prompt_Printf(arg->prompt, " netmask 0x%08lx", (long)ntohl(mask.s_addr)); break; #ifndef NOINET6 case AF_INET6: prompt_Printf(arg->prompt, " inet6 %s", ncpaddr_ntoa(&ncpaddr)); if (ncpaddr_family(&iface->addr[f].peer) != AF_UNSPEC) prompt_Printf(arg->prompt, " --> %s", ncpaddr_ntoa(&iface->addr[f].peer)); ncprange_getwidth(&iface->addr[f].ifa, &width); if (ncpaddr_family(&iface->addr[f].peer) == AF_UNSPEC) prompt_Printf(arg->prompt, " prefixlen %d", width); if ((scopeid = ncprange_scopeid(&iface->addr[f].ifa)) != -1) prompt_Printf(arg->prompt, " scopeid 0x%x", (unsigned)scopeid); break; #endif } prompt_Printf(arg->prompt, "\n"); } return 0; }
int iface_Add(struct iface *iface, struct ncp *ncp, const struct ncprange *ifa, const struct ncpaddr *peer, int how) { int af, removed, s; unsigned n; struct ncpaddr ncplocal; struct iface_addr *addr, newaddr; af = ncprange_family(ifa); if ((s = ID0socket(af, SOCK_DGRAM, 0)) == -1) { log_Printf(LogERROR, "iface_Add: socket(): %s\n", strerror(errno)); return 0; } ncprange_getaddr(ifa, &ncplocal); for (n = 0; n < iface->addrs; n++) { if (ncprange_contains(&iface->addr[n].ifa, &ncplocal) || ncpaddr_equal(&iface->addr[n].peer, peer)) { /* Replace this sockaddr */ if (!(how & IFACE_FORCE_ADD)) { close(s); return 0; /* errno = EEXIST; */ } if (ncprange_equal(&iface->addr[n].ifa, ifa) && ncpaddr_equal(&iface->addr[n].peer, peer)) { close(s); ncp_IfaceAddrAdded(ncp, iface->addr + n); return 1; /* Already there */ } removed = iface_addr_Zap(iface->name, iface->addr + n, s); if (removed) ncp_IfaceAddrDeleted(ncp, iface->addr + n); ncprange_copy(&iface->addr[n].ifa, ifa); ncpaddr_copy(&iface->addr[n].peer, peer); if (!iface_addr_Add(iface->name, iface->addr + n, s)) { if (removed) { bcopy(iface->addr + n + 1, iface->addr + n, (iface->addrs - n - 1) * sizeof *iface->addr); iface->addrs--; n--; } close(s); return 0; } close(s); ncp_IfaceAddrAdded(ncp, iface->addr + n); return 1; } } addr = (struct iface_addr *)realloc (iface->addr, (iface->addrs + 1) * sizeof iface->addr[0]); if (addr == NULL) { log_Printf(LogERROR, "iface_inAdd: realloc: %s\n", strerror(errno)); close(s); return 0; } iface->addr = addr; ncprange_copy(&newaddr.ifa, ifa); ncpaddr_copy(&newaddr.peer, peer); newaddr.system = !!(how & IFACE_SYSTEM); if (!iface_addr_Add(iface->name, &newaddr, s)) { close(s); return 0; } if (how & IFACE_ADD_FIRST) { /* Stuff it at the start of our list */ n = 0; bcopy(iface->addr, iface->addr + 1, iface->addrs * sizeof *iface->addr); } else n = iface->addrs; iface->addrs++; memcpy(iface->addr + n, &newaddr, sizeof(*iface->addr)); close(s); ncp_IfaceAddrAdded(ncp, iface->addr + n); return 1; }
static int iface_addr_Add(const char *name, struct iface_addr *addr, int s) { struct ifaliasreq ifra; #ifndef NOINET6 struct in6_aliasreq ifra6; #endif struct sockaddr_in *me4, *msk4, *peer4; struct sockaddr_storage ssme, sspeer, ssmsk; int res; ncprange_getsa(&addr->ifa, &ssme, &ssmsk); ncpaddr_getsa(&addr->peer, &sspeer); res = 0; switch (ncprange_family(&addr->ifa)) { case AF_INET: memset(&ifra, '\0', sizeof ifra); strncpy(ifra.ifra_name, name, sizeof ifra.ifra_name - 1); me4 = (struct sockaddr_in *)&ifra.ifra_addr; memcpy(me4, &ssme, sizeof *me4); msk4 = (struct sockaddr_in *)&ifra.ifra_mask; memcpy(msk4, &ssmsk, sizeof *msk4); peer4 = (struct sockaddr_in *)&ifra.ifra_broadaddr; if (ncpaddr_family(&addr->peer) == AF_UNSPEC) { peer4->sin_family = AF_INET; peer4->sin_len = sizeof(*peer4); peer4->sin_addr.s_addr = INADDR_NONE; } else memcpy(peer4, &sspeer, sizeof *peer4); res = ID0ioctl(s, SIOCAIFADDR, &ifra); if (log_IsKept(LogDEBUG)) { char buf[100]; snprintf(buf, sizeof buf, "%s", ncprange_ntoa(&addr->ifa)); log_Printf(LogWARN, "%s: AIFADDR %s -> %s returns %d\n", ifra.ifra_name, buf, ncpaddr_ntoa(&addr->peer), res); } break; #ifndef NOINET6 case AF_INET6: memset(&ifra6, '\0', sizeof ifra6); strncpy(ifra6.ifra_name, name, sizeof ifra6.ifra_name - 1); memcpy(&ifra6.ifra_addr, &ssme, sizeof ifra6.ifra_addr); memcpy(&ifra6.ifra_prefixmask, &ssmsk, sizeof ifra6.ifra_prefixmask); if (ncpaddr_family(&addr->peer) == AF_UNSPEC) ifra6.ifra_dstaddr.sin6_family = AF_UNSPEC; else if (memcmp(&((struct sockaddr_in6 *)&ssmsk)->sin6_addr, &in6mask128, sizeof in6mask128) == 0) memcpy(&ifra6.ifra_dstaddr, &sspeer, sizeof ifra6.ifra_dstaddr); ifra6.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME; ifra6.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME; res = ID0ioctl(s, SIOCAIFADDR_IN6, &ifra6); break; #endif } if (res == -1) { char dst[40]; const char *end = #ifndef NOINET6 ncprange_family(&addr->ifa) == AF_INET6 ? "_IN6" : #endif ""; if (ncpaddr_family(&addr->peer) == AF_UNSPEC) log_Printf(LogWARN, "iface add: ioctl(SIOCAIFADDR%s, %s): %s\n", end, ncprange_ntoa(&addr->ifa), strerror(errno)); else { snprintf(dst, sizeof dst, "%s", ncpaddr_ntoa(&addr->peer)); log_Printf(LogWARN, "iface add: ioctl(SIOCAIFADDR%s, %s -> %s): %s\n", end, ncprange_ntoa(&addr->ifa), dst, strerror(errno)); } } return res != -1; }
int main(int argc, char **argv) { char *name; const char *lastlabel; int arg, f, holdfd[3], label; struct bundle *bundle; struct prompt *prompt; struct switches sw; probe_Init(); /* * We open 3 descriptors to ensure that STDIN_FILENO, STDOUT_FILENO and * STDERR_FILENO are always open. These are closed before DoLoop(), * but *after* we've avoided the possibility of erroneously closing * an important descriptor with close(STD{IN,OUT,ERR}_FILENO). */ if ((holdfd[0] = open(_PATH_DEVNULL, O_RDWR)) == -1) { fprintf(stderr, "Cannot open %s !\n", _PATH_DEVNULL); return 2; } for (f = 1; f < sizeof holdfd / sizeof *holdfd; f++) holdfd[f] = dup(holdfd[0]); name = strrchr(argv[0], '/'); log_Open(name ? name + 1 : argv[0]); #ifndef NONAT PacketAliasInit(); #endif label = ProcessArgs(argc, argv, &sw); /* * A FreeBSD & OpenBSD hack to dodge a bug in the tty driver that drops * output occasionally.... I must find the real reason some time. To * display the dodgy behaviour, comment out this bit, make yourself a large * routing table and then run ppp in interactive mode. The `show route' * command will drop chunks of data !!! */ if (sw.mode == PHYS_INTERACTIVE) { close(STDIN_FILENO); if (open(_PATH_TTY, O_RDONLY) != STDIN_FILENO) { fprintf(stderr, "Cannot open %s for input !\n", _PATH_TTY); return 2; } } /* Allow output for the moment (except in direct mode) */ if (sw.mode == PHYS_DIRECT) prompt = NULL; else SignalPrompt = prompt = prompt_Create(NULL, NULL, PROMPT_STD); ID0init(); if (ID0realuid() != 0) { char conf[200], *ptr; snprintf(conf, sizeof conf, "%s/%s", PPP_CONFDIR, CONFFILE); do { struct stat sb; if (stat(conf, &sb) == 0 && sb.st_mode & S_IWOTH) { log_Printf(LogALERT, "ppp: Access violation: Please protect %s\n", conf); return -1; } ptr = conf + strlen(conf)-2; while (ptr > conf && *ptr != '/') *ptr-- = '\0'; } while (ptr >= conf); } if (label < argc) for (arg = label; arg < argc; arg++) CheckLabel(argv[arg], prompt, sw.mode); else CheckLabel("default", prompt, sw.mode); if (!sw.quiet) prompt_Printf(prompt, "Working in %s mode\n", mode2Nam(sw.mode)); if ((bundle = bundle_Create(TUN_PREFIX, sw.mode, sw.unit)) == NULL) return EX_START; /* NOTE: We may now have changed argv[1] via a ``set proctitle'' */ if (prompt) { prompt->bundle = bundle; /* couldn't do it earlier */ if (!sw.quiet) prompt_Printf(prompt, "Using interface: %s\n", bundle->iface->name); } SignalBundle = bundle; bundle->NatEnabled = sw.nat; if (sw.nat) opt_enable(bundle, OPT_IFACEALIAS); if (system_Select(bundle, "default", CONFFILE, prompt, NULL) < 0) prompt_Printf(prompt, "Warning: No default entry found in config file.\n"); sig_signal(SIGHUP, CloseSession); sig_signal(SIGTERM, CloseSession); sig_signal(SIGINT, CloseConnection); sig_signal(SIGQUIT, CloseSession); sig_signal(SIGALRM, SIG_IGN); signal(SIGPIPE, SIG_IGN); if (sw.mode == PHYS_INTERACTIVE) sig_signal(SIGTSTP, TerminalStop); sig_signal(SIGUSR1, RestartServer); sig_signal(SIGUSR2, BringDownServer); lastlabel = argv[argc - 1]; for (arg = label; arg < argc; arg++) { /* In case we use LABEL or ``set enddisc label'' */ bundle_SetLabel(bundle, lastlabel); system_Select(bundle, argv[arg], CONFFILE, prompt, NULL); } if (label < argc) /* In case the last label did a ``load'' */ bundle_SetLabel(bundle, lastlabel); if (sw.mode == PHYS_AUTO && ncprange_family(&bundle->ncp.ipcp.cfg.peer_range) == AF_UNSPEC) { prompt_Printf(prompt, "You must ``set ifaddr'' with a peer address " "in auto mode.\n"); AbortProgram(EX_START); } if (sw.mode != PHYS_INTERACTIVE) { if (sw.mode != PHYS_DIRECT) { if (!sw.fg) { int bgpipe[2]; pid_t bgpid; if (sw.mode == PHYS_BACKGROUND && pipe(bgpipe)) { log_Printf(LogERROR, "pipe: %s\n", strerror(errno)); AbortProgram(EX_SOCK); } bgpid = fork(); if (bgpid == -1) { log_Printf(LogERROR, "fork: %s\n", strerror(errno)); AbortProgram(EX_SOCK); } if (bgpid) { char c = EX_NORMAL; int ret; if (sw.mode == PHYS_BACKGROUND) { close(bgpipe[1]); BGPid = bgpid; /* If we get a signal, kill the child */ signal(SIGHUP, KillChild); signal(SIGTERM, KillChild); signal(SIGINT, KillChild); signal(SIGQUIT, KillChild); /* Wait for our child to close its pipe before we exit */ while ((ret = read(bgpipe[0], &c, 1)) == 1) { switch (c) { case EX_NORMAL: if (!sw.quiet) { prompt_Printf(prompt, "PPP enabled\n"); log_Printf(LogPHASE, "Parent: PPP enabled\n"); } break; case EX_REDIAL: if (!sw.quiet) prompt_Printf(prompt, "Attempting redial\n"); continue; case EX_RECONNECT: if (!sw.quiet) prompt_Printf(prompt, "Attempting reconnect\n"); continue; default: prompt_Printf(prompt, "Child failed (%s)\n", ex_desc((int)c)); log_Printf(LogPHASE, "Parent: Child failed (%s)\n", ex_desc((int) c)); } break; } if (ret != 1) { prompt_Printf(prompt, "Child exit, no status.\n"); log_Printf(LogPHASE, "Parent: Child exit, no status.\n"); } close(bgpipe[0]); } return c; } else if (sw.mode == PHYS_BACKGROUND) { close(bgpipe[0]); bundle->notify.fd = bgpipe[1]; } bundle_ChangedPID(bundle); bundle_LockTun(bundle); /* we have a new pid */ } /* -auto, -dedicated, -ddial, -foreground & -background */ prompt_Destroy(prompt, 0); close(STDOUT_FILENO); close(STDERR_FILENO); close(STDIN_FILENO); if (!sw.fg) setsid(); } else { /* -direct - STDIN_FILENO gets used by physical_Open */ prompt_TtyInit(NULL); close(STDOUT_FILENO); close(STDERR_FILENO); } } else { /* -interactive */ close(STDERR_FILENO); prompt_TtyInit(prompt); prompt_TtyCommandMode(prompt); prompt_Required(prompt); } /* We can get rid of these now */ for (f = 0; f < sizeof holdfd / sizeof *holdfd; f++) close(holdfd[f]); log_Printf(LogPHASE, "PPP Started (%s mode).\n", mode2Nam(sw.mode)); DoLoop(bundle); AbortProgram(EX_NORMAL); return EX_NORMAL; }
static int filter_Parse(struct ncp *ncp, int argc, char const *const *argv, struct filterent *ofp) { struct filterent fe; struct protoent *pe; char *wp; int action, family, ruleno, val, width; ruleno = strtol(*argv, &wp, 0); if (*argv == wp || ruleno >= MAXFILTERS) { log_Printf(LogWARN, "Parse: invalid filter number.\n"); return 0; } if (ruleno < 0) { for (ruleno = 0; ruleno < MAXFILTERS; ruleno++) { ofp->f_action = A_NONE; ofp++; } log_Printf(LogWARN, "Parse: filter cleared.\n"); return 1; } ofp += ruleno; if (--argc == 0) { log_Printf(LogWARN, "Parse: missing action.\n"); return 0; } argv++; memset(&fe, '\0', sizeof fe); val = strtol(*argv, &wp, 0); if (!*wp && val >= 0 && val < MAXFILTERS) { if (val <= ruleno) { log_Printf(LogWARN, "Parse: Can only jump forward from rule %d\n", ruleno); return 0; } action = val; } else if (!strcmp(*argv, "permit")) { action = A_PERMIT; } else if (!strcmp(*argv, "deny")) { action = A_DENY; } else if (!strcmp(*argv, "clear")) { ofp->f_action = A_NONE; return 1; } else { log_Printf(LogWARN, "Parse: %s: bad action\n", *argv); return 0; } fe.f_action = action; argc--; argv++; if (argc && argv[0][0] == '!' && !argv[0][1]) { fe.f_invert = 1; argc--; argv++; } ncprange_init(&fe.f_src); ncprange_init(&fe.f_dst); if (argc == 0) pe = NULL; else if ((pe = getprotobyname(*argv)) == NULL && strcmp(*argv, "all") != 0) { if (argc < 2) { log_Printf(LogWARN, "Parse: Protocol or address pair expected\n"); return 0; } else if (strcasecmp(*argv, "any") == 0 || ncprange_aton(&fe.f_src, ncp, *argv)) { family = ncprange_family(&fe.f_src); if (!ncprange_getwidth(&fe.f_src, &width)) width = 0; if (width == 0) ncprange_init(&fe.f_src); fe.f_srctype = addrtype(*argv); argc--; argv++; if (strcasecmp(*argv, "any") == 0 || ncprange_aton(&fe.f_dst, ncp, *argv)) { if (ncprange_family(&fe.f_dst) != AF_UNSPEC && ncprange_family(&fe.f_src) != AF_UNSPEC && family != ncprange_family(&fe.f_dst)) { log_Printf(LogWARN, "Parse: src and dst address families differ\n"); return 0; } if (!ncprange_getwidth(&fe.f_dst, &width)) width = 0; if (width == 0) ncprange_init(&fe.f_dst); fe.f_dsttype = addrtype(*argv); argc--; argv++; } else { log_Printf(LogWARN, "Parse: Protocol or address pair expected\n"); return 0; } if (argc) { if ((pe = getprotobyname(*argv)) == NULL && strcmp(*argv, "all") != 0) { log_Printf(LogWARN, "Parse: %s: Protocol expected\n", *argv); return 0; } else { argc--; argv++; } } } else { log_Printf(LogWARN, "Parse: Protocol or address pair expected\n"); return 0; } } else { argc--; argv++; } if (argc >= 2 && strcmp(*argv, "timeout") == 0) { fe.timeout = strtoul(argv[1], NULL, 10); argc -= 2; argv += 2; } val = 1; fe.f_proto = (pe == NULL) ? 0 : pe->p_proto; switch (fe.f_proto) { case IPPROTO_TCP: case IPPROTO_UDP: case IPPROTO_IPIP: #ifndef NOINET6 case IPPROTO_IPV6: #endif val = ParseUdpOrTcp(argc, argv, pe, &fe); break; case IPPROTO_ICMP: #ifndef NOINET6 case IPPROTO_ICMPV6: #endif val = ParseIcmp(argc, argv, &fe); break; default: val = ParseGeneric(argc, &fe); break; } log_Printf(LogDEBUG, "Parse: Src: %s\n", ncprange_ntoa(&fe.f_src)); log_Printf(LogDEBUG, "Parse: Dst: %s\n", ncprange_ntoa(&fe.f_dst)); log_Printf(LogDEBUG, "Parse: Proto: %d\n", fe.f_proto); log_Printf(LogDEBUG, "Parse: src: %s (%d)\n", filter_Op2Nam(fe.f_srcop), fe.f_srcport); log_Printf(LogDEBUG, "Parse: dst: %s (%d)\n", filter_Op2Nam(fe.f_dstop), fe.f_dstport); log_Printf(LogDEBUG, "Parse: estab: %u\n", fe.f_estab); log_Printf(LogDEBUG, "Parse: syn: %u\n", fe.f_syn); log_Printf(LogDEBUG, "Parse: finrst: %u\n", fe.f_finrst); if (val) *ofp = fe; return val; }
void ncp_IfaceAddrDeleted(struct ncp *ncp, const struct iface_addr *addr) { if (ncprange_family(&addr->ifa) == AF_INET) ipcp_IfaceAddrDeleted(&ncp->ipcp, addr); }