Beispiel #1
0
int
arp_EtherAddr(int s, struct in_addr ipaddr, struct sockaddr_dl *hwaddr,
              int verbose)
{
  int mib[6], skip;
  size_t needed;
  char *buf, *ptr, *end;
  struct if_msghdr *ifm;
  struct ifa_msghdr *ifam;
  struct sockaddr_dl *dl;
  struct sockaddr *sa[RTAX_MAX];

  mib[0] = CTL_NET;
  mib[1] = PF_ROUTE;
  mib[2] = 0;
  mib[3] = 0;
  mib[4] = NET_RT_IFLIST;
  mib[5] = 0;

  if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
    log_Printf(LogERROR, "arp_EtherAddr: sysctl: estimate: %s\n",
              strerror(errno));
    return 0;
  }

  if ((buf = malloc(needed)) == NULL)
    return 0;

  if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
    free(buf);
    return 0;
  }
  end = buf + needed;

  ptr = buf;
  while (ptr < end) {
    ifm = (struct if_msghdr *)ptr;		/* On if_msghdr */
    if (ifm->ifm_type != RTM_IFINFO)
      break;
    dl = (struct sockaddr_dl *)(ifm + 1);	/* Single _dl at end */
    skip = (ifm->ifm_flags & (IFF_UP | IFF_BROADCAST | IFF_POINTOPOINT |
            IFF_NOARP | IFF_LOOPBACK)) != (IFF_UP | IFF_BROADCAST);
    ptr += ifm->ifm_msglen;			/* First ifa_msghdr */
    while (ptr < end) {
      ifam = (struct ifa_msghdr *)ptr;	/* Next ifa_msghdr (alias) */
      if (ifam->ifam_type != RTM_NEWADDR)	/* finished ? */
        break;
      ptr += ifam->ifam_msglen;
      if (skip || (ifam->ifam_addrs & (RTA_NETMASK|RTA_IFA)) !=
          (RTA_NETMASK|RTA_IFA))
        continue;
      /* Found a candidate.  Do the addresses match ? */
      if (log_IsKept(LogDEBUG) &&
          ptr == (char *)ifm + ifm->ifm_msglen + ifam->ifam_msglen)
        log_Printf(LogDEBUG, "%.*s interface is a candidate for proxy\n",
                  dl->sdl_nlen, dl->sdl_data);

      iface_ParseHdr(ifam, sa);

      if (sa[RTAX_IFA]->sa_family == AF_INET) {
        struct sockaddr_in *ifa, *netmask;

        ifa = (struct sockaddr_in *)sa[RTAX_IFA];
        netmask = (struct sockaddr_in *)sa[RTAX_NETMASK];

        if (log_IsKept(LogDEBUG)) {
          char a[16];

          strncpy(a, inet_ntoa(netmask->sin_addr), sizeof a - 1);
          a[sizeof a - 1] = '\0';
          log_Printf(LogDEBUG, "Check addr %s, mask %s\n",
                     inet_ntoa(ifa->sin_addr), a);
        }

        if ((ifa->sin_addr.s_addr & netmask->sin_addr.s_addr) ==
            (ipaddr.s_addr & netmask->sin_addr.s_addr)) {
          log_Printf(verbose ? LogPHASE : LogDEBUG,
                     "Found interface %.*s for %s\n", dl->sdl_alen,
                     dl->sdl_data, inet_ntoa(ipaddr));
          memcpy(hwaddr, dl, dl->sdl_len);
          free(buf);
          return 1;
        }
      }
    }
  }
  free(buf);

  return 0;
}
Beispiel #2
0
static void
p_sockaddr(struct prompt *prompt, struct sockaddr *phost,
           struct sockaddr *pmask, int width)
{
    struct ncprange range;
    char buf[29];
    struct sockaddr_dl *dl = (struct sockaddr_dl *)phost;

    if (log_IsKept(LogDEBUG)) {
        char tmp[50];

        log_Printf(LogDEBUG, "Found the following sockaddr:\n");
        log_Printf(LogDEBUG, "  Family %d, len %d\n",
                   (int)phost->sa_family, (int)phost->sa_len);
        inet_ntop(phost->sa_family, phost->sa_data, tmp, sizeof tmp);
        log_Printf(LogDEBUG, "  Addr %s\n", tmp);
        if (pmask) {
            inet_ntop(pmask->sa_family, pmask->sa_data, tmp, sizeof tmp);
            log_Printf(LogDEBUG, "  Mask %s\n", tmp);
        }
    }

    switch (phost->sa_family) {
    case AF_INET:
#ifndef NOINET6
    case AF_INET6:
#endif
        ncprange_setsa(&range, phost, pmask);
        if (ncprange_isdefault(&range))
            prompt_Printf(prompt, "%-*s ", width - 1, "default");
        else
            prompt_Printf(prompt, "%-*s ", width - 1, ncprange_ntoa(&range));
        return;

    case AF_LINK:
        if (dl->sdl_nlen)
            snprintf(buf, sizeof buf, "%.*s", dl->sdl_nlen, dl->sdl_data);
        else if (dl->sdl_alen) {
            if (dl->sdl_type == IFT_ETHER) {
                if (dl->sdl_alen < sizeof buf / 3) {
                    int f;
                    u_char *MAC;

                    MAC = (u_char *)dl->sdl_data + dl->sdl_nlen;
                    for (f = 0; f < dl->sdl_alen; f++)
                        sprintf(buf+f*3, "%02x:", MAC[f]);
                    buf[f*3-1] = '\0';
                } else
                    strcpy(buf, "??:??:??:??:??:??");
            } else
                sprintf(buf, "<IFT type %d>", dl->sdl_type);
        }  else if (dl->sdl_slen)
            sprintf(buf, "<slen %d?>", dl->sdl_slen);
        else
            sprintf(buf, "link#%d", dl->sdl_index);
        break;

    default:
        sprintf(buf, "<AF type %d>", phost->sa_family);
        break;
    }

    prompt_Printf(prompt, "%-*s ", width-1, buf);
}
Beispiel #3
0
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;
}
Beispiel #4
0
int
rt_Set(struct bundle *bundle, int cmd, const struct ncprange *dst,
       const struct ncpaddr *gw, int bang, int quiet)
{
    struct rtmsg rtmes;
    int s, nb, wb;
    char *cp;
    const char *cmdstr;
    struct sockaddr_storage sadst, samask, sagw;
    int result = 1;

    if (bang)
        cmdstr = (cmd == RTM_ADD ? "Add!" : "Delete!");
    else
        cmdstr = (cmd == RTM_ADD ? "Add" : "Delete");
    s = ID0socket(PF_ROUTE, SOCK_RAW, 0);
    if (s < 0) {
        log_Printf(LogERROR, "rt_Set: socket(): %s\n", strerror(errno));
        return result;
    }
    memset(&rtmes, '\0', sizeof rtmes);
    rtmes.m_rtm.rtm_version = RTM_VERSION;
    rtmes.m_rtm.rtm_type = cmd;
    rtmes.m_rtm.rtm_addrs = RTA_DST;
    rtmes.m_rtm.rtm_seq = ++bundle->routing_seq;
    rtmes.m_rtm.rtm_pid = getpid();
    rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC;

    if (cmd == RTM_ADD) {
        if (bundle->ncp.cfg.sendpipe > 0) {
            rtmes.m_rtm.rtm_rmx.rmx_sendpipe = bundle->ncp.cfg.sendpipe;
            rtmes.m_rtm.rtm_inits |= RTV_SPIPE;
        }
        if (bundle->ncp.cfg.recvpipe > 0) {
            rtmes.m_rtm.rtm_rmx.rmx_recvpipe = bundle->ncp.cfg.recvpipe;
            rtmes.m_rtm.rtm_inits |= RTV_RPIPE;
        }
    }

    ncprange_getsa(dst, &sadst, &samask);
#if defined(__KAME__) && !defined(NOINET6)
    add_scope((struct sockaddr *)&sadst, bundle->iface->index);
#endif

    cp = rtmes.m_space;
    cp += memcpy_roundup(cp, &sadst, sadst.ss_len);
    if (cmd == RTM_ADD) {
        if (gw == NULL) {
            log_Printf(LogERROR, "rt_Set: Program error\n");
            close(s);
            return result;
        }
        ncpaddr_getsa(gw, &sagw);
#if defined(__KAME__) && !defined(NOINET6)
        add_scope((struct sockaddr *)&sagw, bundle->iface->index);
#endif
        if (ncpaddr_isdefault(gw)) {
            if (!quiet)
                log_Printf(LogERROR, "rt_Set: Cannot add a route with"
                           " gateway 0.0.0.0\n");
            close(s);
            return result;
        } else {
            cp += memcpy_roundup(cp, &sagw, sagw.ss_len);
            rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY;
        }
    }

    if (!ncprange_ishost(dst)) {
        cp += memcpy_roundup(cp, &samask, samask.ss_len);
        rtmes.m_rtm.rtm_addrs |= RTA_NETMASK;
    }

    nb = cp - (char *)&rtmes;
    rtmes.m_rtm.rtm_msglen = nb;
    wb = ID0write(s, &rtmes, nb);
    if (wb < 0) {
        log_Printf(LogTCPIP, "rt_Set failure:\n");
        log_Printf(LogTCPIP, "rt_Set:  Cmd = %s\n", cmdstr);
        log_Printf(LogTCPIP, "rt_Set:  Dst = %s\n", ncprange_ntoa(dst));
        if (gw != NULL)
            log_Printf(LogTCPIP, "rt_Set:  Gateway = %s\n", ncpaddr_ntoa(gw));
failed:
        if (cmd == RTM_ADD && (rtmes.m_rtm.rtm_errno == EEXIST ||
                               (rtmes.m_rtm.rtm_errno == 0 && errno == EEXIST))) {
            if (!bang) {
                log_Printf(LogWARN, "Add route failed: %s already exists\n",
                           ncprange_ntoa(dst));
                result = 0;	/* Don't add to our dynamic list */
            } else {
                rtmes.m_rtm.rtm_type = cmd = RTM_CHANGE;
                if ((wb = ID0write(s, &rtmes, nb)) < 0)
                    goto failed;
            }
        } else if (cmd == RTM_DELETE &&
                   (rtmes.m_rtm.rtm_errno == ESRCH ||
                    (rtmes.m_rtm.rtm_errno == 0 && errno == ESRCH))) {
            if (!bang)
                log_Printf(LogWARN, "Del route failed: %s: Non-existent\n",
                           ncprange_ntoa(dst));
        } else if (rtmes.m_rtm.rtm_errno == 0) {
            if (!quiet || errno != ENETUNREACH)
                log_Printf(LogWARN, "%s route failed: %s: errno: %s\n", cmdstr,
                           ncprange_ntoa(dst), strerror(errno));
        } else
            log_Printf(LogWARN, "%s route failed: %s: %s\n",
                       cmdstr, ncprange_ntoa(dst), strerror(rtmes.m_rtm.rtm_errno));
    }

    if (log_IsKept(LogDEBUG)) {
        char gwstr[40];

        if (gw)
            snprintf(gwstr, sizeof gwstr, "%s", ncpaddr_ntoa(gw));
        else
            snprintf(gwstr, sizeof gwstr, "<none>");
        log_Printf(LogDEBUG, "wrote %d: cmd = %s, dst = %s, gateway = %s\n",
                   wb, cmdstr, ncprange_ntoa(dst), gwstr);
    }
    close(s);

    return result;
}
Beispiel #5
0
/*
 *  Delete routes associated with our interface
 */
void
route_IfDelete(struct bundle *bundle, int all)
{
    struct rt_msghdr *rtm;
    struct sockaddr *sa[RTAX_MAX];
    struct ncprange range;
    int pass;
    size_t needed;
    char *sp, *cp, *ep;
    int mib[6];

    log_Printf(LogDEBUG, "route_IfDelete (%d)\n", bundle->iface->index);

    mib[0] = CTL_NET;
    mib[1] = PF_ROUTE;
    mib[2] = 0;
    mib[3] = 0;
    mib[4] = NET_RT_DUMP;
    mib[5] = 0;
    if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
        log_Printf(LogERROR, "route_IfDelete: sysctl: estimate: %s\n",
                   strerror(errno));
        return;
    }

    sp = malloc(needed);
    if (sp == NULL)
        return;

    if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) {
        log_Printf(LogERROR, "route_IfDelete: sysctl: getroute: %s\n",
                   strerror(errno));
        free(sp);
        return;
    }
    ep = sp + needed;

    for (pass = 0; pass < 2; pass++) {
        /*
         * We do 2 passes.  The first deletes all cloned routes.  The second
         * deletes all non-cloned routes.  This is done to avoid
         * potential errors from trying to delete route X after route Y where
         * route X was cloned from route Y (and is no longer there 'cos it
         * may have gone with route Y).
         */
        if (pass == 0)
            /* So we can't tell ! */
            continue;
        for (cp = sp; cp < ep; cp += rtm->rtm_msglen) {
            rtm = (struct rt_msghdr *)cp;
            route_ParseHdr(rtm, sa);
            if (rtm->rtm_index == bundle->iface->index &&
                    sa[RTAX_DST] && sa[RTAX_GATEWAY] &&
                    (sa[RTAX_DST]->sa_family == AF_INET
#ifndef NOINET6
                     || sa[RTAX_DST]->sa_family == AF_INET6
#endif
                    ) &&
                    (all || (rtm->rtm_flags & RTF_GATEWAY))) {
                if (log_IsKept(LogDEBUG)) {
                    char gwstr[41];
                    struct ncpaddr gw;
                    ncprange_setsa(&range, sa[RTAX_DST], sa[RTAX_NETMASK]);
                    ncpaddr_setsa(&gw, sa[RTAX_GATEWAY]);
                    snprintf(gwstr, sizeof gwstr, "%s", ncpaddr_ntoa(&gw));
                    log_Printf(LogDEBUG, "Found %s %s\n", ncprange_ntoa(&range), gwstr);
                }
                if (sa[RTAX_GATEWAY]->sa_family == AF_INET ||
#ifndef NOINET6
                        sa[RTAX_GATEWAY]->sa_family == AF_INET6 ||
#endif
                        sa[RTAX_GATEWAY]->sa_family == AF_LINK) {
                    if (pass == 1) {
                        ncprange_setsa(&range, sa[RTAX_DST], sa[RTAX_NETMASK]);
                        rt_Set(bundle, RTM_DELETE, &range, NULL, 0, 0);
                    } else
                        log_Printf(LogDEBUG, "route_IfDelete: Skip it (pass %d)\n", pass);
                } else
                    log_Printf(LogDEBUG,
                               "route_IfDelete: Can't remove routes for family %d\n",
                               sa[RTAX_GATEWAY]->sa_family);
            }
        }
    }
    free(sp);
}
Beispiel #6
0
const char *
Index2Nam(int idx)
{
    /*
     * XXX: Maybe we should select() on the routing socket so that we can
     *      notice interfaces that come & go (PCCARD support).
     *      Or we could even support a signal that resets these so that
     *      the PCCARD insert/remove events can signal ppp.
     */
    static char **ifs;		/* Figure these out once */
    static int debug_done;	/* Debug once */

    if (idx > route_nifs || (idx > 0 && ifs[idx-1] == NULL)) {
        int mib[6], have, had;
        size_t needed;
        char *buf, *ptr, *end;
        struct sockaddr_dl *dl;
        struct if_msghdr *ifm;

        if (ifs) {
            free(ifs);
            ifs = NULL;
            route_nifs = 0;
        }
        debug_done = 0;

        mib[0] = CTL_NET;
        mib[1] = PF_ROUTE;
        mib[2] = 0;
        mib[3] = 0;
        mib[4] = NET_RT_IFLIST;
        mib[5] = 0;

        if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
            log_Printf(LogERROR, "Index2Nam: sysctl: estimate: %s\n",
                       strerror(errno));
            return NumStr(idx, NULL, 0);
        }
        if ((buf = malloc(needed)) == NULL)
            return NumStr(idx, NULL, 0);
        if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
            free(buf);
            return NumStr(idx, NULL, 0);
        }
        end = buf + needed;

        have = 0;
        for (ptr = buf; ptr < end; ptr += ifm->ifm_msglen) {
            ifm = (struct if_msghdr *)ptr;
            if (ifm->ifm_type != RTM_IFINFO)
                continue;
            dl = (struct sockaddr_dl *)(ifm + 1);
            if (ifm->ifm_index > 0) {
                if (ifm->ifm_index > have) {
                    char **newifs;

                    had = have;
                    have = ifm->ifm_index + 5;
                    if (had)
                        newifs = (char **)realloc(ifs, sizeof(char *) * have);
                    else
                        newifs = (char **)malloc(sizeof(char *) * have);
                    if (!newifs) {
                        log_Printf(LogDEBUG, "Index2Nam: %s\n", strerror(errno));
                        route_nifs = 0;
                        if (ifs) {
                            free(ifs);
                            ifs = NULL;
                        }
                        free(buf);
                        return NumStr(idx, NULL, 0);
                    }
                    ifs = newifs;
                    memset(ifs + had, '\0', sizeof(char *) * (have - had));
                }
                if (ifs[ifm->ifm_index-1] == NULL) {
                    ifs[ifm->ifm_index-1] = (char *)malloc(dl->sdl_nlen+1);
                    if (ifs[ifm->ifm_index-1] == NULL)
                        log_Printf(LogDEBUG, "Skipping interface %d: Out of memory\n",
                                   ifm->ifm_index);
                    else {
                        memcpy(ifs[ifm->ifm_index-1], dl->sdl_data, dl->sdl_nlen);
                        ifs[ifm->ifm_index-1][dl->sdl_nlen] = '\0';
                        if (route_nifs < ifm->ifm_index)
                            route_nifs = ifm->ifm_index;
                    }
                }
            } else if (log_IsKept(LogDEBUG))
                log_Printf(LogDEBUG, "Skipping out-of-range interface %d!\n",
                           ifm->ifm_index);
        }
        free(buf);
    }

    if (log_IsKept(LogDEBUG) && !debug_done) {
        int f;

        log_Printf(LogDEBUG, "Found the following interfaces:\n");
        for (f = 0; f < route_nifs; f++)
            if (ifs[f] != NULL)
                log_Printf(LogDEBUG, " Index %d, name \"%s\"\n", f+1, ifs[f]);
        debug_done = 1;
    }

    if (idx < 1 || idx > route_nifs || ifs[idx-1] == NULL)
        return NumStr(idx, NULL, 0);

    return ifs[idx-1];
}
Beispiel #7
0
/*
 * rad_continue_send_request() has given us `got' (non-zero).  Deal with it.
 */
static void
radius_Process(struct radius *r, int got)
{
  char *argv[MAXARGS], *nuke;
  struct bundle *bundle;
  int argc, addrs, res, width;
  size_t len;
  struct ncprange dest;
  struct ncpaddr gw;
  const void *data;
  const char *stype;
  u_int32_t ipaddr, vendor;
  struct in_addr ip;
#ifndef NOINET6
  uint8_t ipv6addr[INET6_ADDRSTRLEN];
  struct in6_addr ip6;
#endif

  r->cx.fd = -1;		/* Stop select()ing */
  stype = r->cx.auth ? "auth" : "acct";

  switch (got) {
    case RAD_ACCESS_ACCEPT:
      log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
		 "Radius(%s): ACCEPT received\n", stype);
      if (!r->cx.auth) {
        rad_close(r->cx.rad);
        return;
      }
      break;

    case RAD_ACCESS_REJECT:
      log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
		 "Radius(%s): REJECT received\n", stype);
      if (!r->cx.auth) {
        rad_close(r->cx.rad);
        return;
      }
      break;

    case RAD_ACCESS_CHALLENGE:
      /* we can't deal with this (for now) ! */
      log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
		 "Radius: CHALLENGE received (can't handle yet)\n");
      if (r->cx.auth)
        auth_Failure(r->cx.auth);
      rad_close(r->cx.rad);
      return;

    case RAD_ACCOUNTING_RESPONSE:
      /*
       * It's probably not ideal to log this at PHASE level as we'll see
       * too much stuff going to the log when ``set rad_alive'' is used.
       * So we differ from older behaviour (ppp version 3.1 and before)
       * and just log accounting responses to LogRADIUS.
       */
      log_Printf(LogRADIUS, "Radius(%s): Accounting response received\n",
		 stype);
      if (r->cx.auth)
        auth_Failure(r->cx.auth);		/* unexpected !!! */

      /* No further processing for accounting requests, please */
      rad_close(r->cx.rad);
      return;

    case -1:
      log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
		 "radius(%s): %s\n", stype, rad_strerror(r->cx.rad));
      if (r->cx.auth)
        auth_Failure(r->cx.auth);
      rad_close(r->cx.rad);
      return;

    default:
      log_Printf(LogERROR, "rad_send_request(%s): Failed %d: %s\n", stype,
                 got, rad_strerror(r->cx.rad));
      if (r->cx.auth)
        auth_Failure(r->cx.auth);
      rad_close(r->cx.rad);
      return;
  }

  /* Let's see what we've got in our reply */
  r->ip.s_addr = r->mask.s_addr = INADDR_NONE;
  r->mtu = 0;
  r->vj = 0;
  while ((res = rad_get_attr(r->cx.rad, &data, &len)) > 0) {
    switch (res) {
      case RAD_FRAMED_IP_ADDRESS:
        r->ip = rad_cvt_addr(data);
	log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
		   " IP %s\n", inet_ntoa(r->ip));
        break;

      case RAD_FILTER_ID:
        free(r->filterid);
        if ((r->filterid = rad_cvt_string(data, len)) == NULL) {
          log_Printf(LogERROR, "rad_cvt_string: %s\n", rad_strerror(r->cx.rad));
          auth_Failure(r->cx.auth);
          rad_close(r->cx.rad);
          return;
        }
	log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
		   " Filter \"%s\"\n", r->filterid);
        break;

      case RAD_SESSION_TIMEOUT:
        r->sessiontime = rad_cvt_int(data);
	log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
		   " Session-Timeout %lu\n", r->sessiontime);
        break;

      case RAD_FRAMED_IP_NETMASK:
        r->mask = rad_cvt_addr(data);
	log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
		   " Netmask %s\n", inet_ntoa(r->mask));
        break;

      case RAD_FRAMED_MTU:
        r->mtu = rad_cvt_int(data);
	log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
		   " MTU %lu\n", r->mtu);
        break;

      case RAD_FRAMED_ROUTING:
        /* Disabled for now - should we automatically set up some filters ? */
        /* rad_cvt_int(data); */
        /* bit 1 = Send routing packets */
        /* bit 2 = Receive routing packets */
        break;

      case RAD_FRAMED_COMPRESSION:
        r->vj = rad_cvt_int(data) == 1 ? 1 : 0;
	log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
		   " VJ %sabled\n", r->vj ? "en" : "dis");
        break;

      case RAD_FRAMED_ROUTE:
        /*
         * We expect a string of the format ``dest[/bits] gw [metrics]''
         * Any specified metrics are ignored.  MYADDR and HISADDR are
         * understood for ``dest'' and ``gw'' and ``0.0.0.0'' is the same
         * as ``HISADDR''.
         */

        if ((nuke = rad_cvt_string(data, len)) == NULL) {
          log_Printf(LogERROR, "rad_cvt_string: %s\n", rad_strerror(r->cx.rad));
          auth_Failure(r->cx.auth);
          rad_close(r->cx.rad);
          return;
        }

	log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
		   " Route: %s\n", nuke);
        bundle = r->cx.auth->physical->dl->bundle;
        ip.s_addr = INADDR_ANY;
        ncpaddr_setip4(&gw, ip);
        ncprange_setip4host(&dest, ip);
        argc = command_Interpret(nuke, strlen(nuke), argv);
        if (argc < 0)
          log_Printf(LogWARN, "radius: %s: Syntax error\n",
                     argc == 1 ? argv[0] : "\"\"");
        else if (argc < 2)
          log_Printf(LogWARN, "radius: %s: Invalid route\n",
                     argc == 1 ? argv[0] : "\"\"");
        else if ((strcasecmp(argv[0], "default") != 0 &&
                  !ncprange_aton(&dest, &bundle->ncp, argv[0])) ||
                 !ncpaddr_aton(&gw, &bundle->ncp, argv[1]))
          log_Printf(LogWARN, "radius: %s %s: Invalid route\n",
                     argv[0], argv[1]);
        else {
          ncprange_getwidth(&dest, &width);
          if (width == 32 && strchr(argv[0], '/') == NULL) {
            /* No mask specified - use the natural mask */
            ncprange_getip4addr(&dest, &ip);
            ncprange_setip4mask(&dest, addr2mask(ip));
          }
          addrs = 0;

          if (!strncasecmp(argv[0], "HISADDR", 7))
            addrs = ROUTE_DSTHISADDR;
          else if (!strncasecmp(argv[0], "MYADDR", 6))
            addrs = ROUTE_DSTMYADDR;

          if (ncpaddr_getip4addr(&gw, &ipaddr) && ipaddr == INADDR_ANY) {
            addrs |= ROUTE_GWHISADDR;
            ncpaddr_setip4(&gw, bundle->ncp.ipcp.peer_ip);
          } else if (strcasecmp(argv[1], "HISADDR") == 0)
            addrs |= ROUTE_GWHISADDR;

          route_Add(&r->routes, addrs, &dest, &gw);
        }
        free(nuke);
        break;

      case RAD_REPLY_MESSAGE:
        free(r->repstr);
        if ((r->repstr = rad_cvt_string(data, len)) == NULL) {
          log_Printf(LogERROR, "rad_cvt_string: %s\n", rad_strerror(r->cx.rad));
          auth_Failure(r->cx.auth);
          rad_close(r->cx.rad);
          return;
        }
	log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
		   " Reply-Message \"%s\"\n", r->repstr);
        break;

#ifndef NOINET6
      case RAD_FRAMED_IPV6_PREFIX:
	free(r->ipv6prefix);
	if ((r->ipv6prefix = rad_cvt_ipv6prefix(data, len)) == NULL) {
	  log_Printf(LogERROR, "rad_cvt_ipv6prefix: %s\n",
		     "Malformed attribute in response");
	  auth_Failure(r->cx.auth);
	  rad_close(r->cx.rad);
	  return;
	}
	inet_ntop(AF_INET6, &r->ipv6prefix[2], ipv6addr, sizeof(ipv6addr));
	log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
		   " IPv6 %s/%d\n", ipv6addr, r->ipv6prefix[1]);
        break;

      case RAD_FRAMED_IPV6_ROUTE:
        /*
         * We expect a string of the format ``dest[/bits] gw [metrics]''
         * Any specified metrics are ignored.  MYADDR6 and HISADDR6 are
         * understood for ``dest'' and ``gw'' and ``::'' is the same
         * as ``HISADDR6''.
         */

        if ((nuke = rad_cvt_string(data, len)) == NULL) {
          log_Printf(LogERROR, "rad_cvt_string: %s\n", rad_strerror(r->cx.rad));
          auth_Failure(r->cx.auth);
          rad_close(r->cx.rad);
          return;
        }

	log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
		   " IPv6 Route: %s\n", nuke);
        bundle = r->cx.auth->physical->dl->bundle;
	ncpaddr_setip6(&gw, &in6addr_any);
	ncprange_set(&dest, &gw, 0);
        argc = command_Interpret(nuke, strlen(nuke), argv);
        if (argc < 0)
          log_Printf(LogWARN, "radius: %s: Syntax error\n",
                     argc == 1 ? argv[0] : "\"\"");
        else if (argc < 2)
          log_Printf(LogWARN, "radius: %s: Invalid route\n",
                     argc == 1 ? argv[0] : "\"\"");
        else if ((strcasecmp(argv[0], "default") != 0 &&
                  !ncprange_aton(&dest, &bundle->ncp, argv[0])) ||
                 !ncpaddr_aton(&gw, &bundle->ncp, argv[1]))
          log_Printf(LogWARN, "radius: %s %s: Invalid route\n",
                     argv[0], argv[1]);
        else {
          addrs = 0;

          if (!strncasecmp(argv[0], "HISADDR6", 8))
            addrs = ROUTE_DSTHISADDR6;
          else if (!strncasecmp(argv[0], "MYADDR6", 7))
            addrs = ROUTE_DSTMYADDR6;

          if (ncpaddr_getip6(&gw, &ip6) && IN6_IS_ADDR_UNSPECIFIED(&ip6)) {
            addrs |= ROUTE_GWHISADDR6;
            ncpaddr_copy(&gw, &bundle->ncp.ipv6cp.hisaddr);
          } else if (strcasecmp(argv[1], "HISADDR6") == 0)
            addrs |= ROUTE_GWHISADDR6;

          route_Add(&r->ipv6routes, addrs, &dest, &gw);
        }
        free(nuke);
        break;
#endif

      case RAD_VENDOR_SPECIFIC:
        if ((res = rad_get_vendor_attr(&vendor, &data, &len)) <= 0) {
          log_Printf(LogERROR, "rad_get_vendor_attr: %s (failing!)\n",
                     rad_strerror(r->cx.rad));
          auth_Failure(r->cx.auth);
          rad_close(r->cx.rad);
          return;
        }

	switch (vendor) {
          case RAD_VENDOR_MICROSOFT:
            switch (res) {
#ifndef NODES
              case RAD_MICROSOFT_MS_CHAP_ERROR:
                free(r->errstr);
                if (len == 0)
                  r->errstr = NULL;
                else {
                  if (len < 3 || ((const char *)data)[1] != '=') {
                    /*
                     * Only point at the String field if we don't think the
                     * peer has misformatted the response.
                     */
                    data = (const char *)data + 1;
                    len--;
                  } else
                    log_Printf(LogWARN, "Warning: The MS-CHAP-Error "
                               "attribute is mis-formatted.  Compensating\n");
                  if ((r->errstr = rad_cvt_string((const char *)data,
                                                  len)) == NULL) {
                    log_Printf(LogERROR, "rad_cvt_string: %s\n",
                               rad_strerror(r->cx.rad));
                    auth_Failure(r->cx.auth);
                    rad_close(r->cx.rad);
                    return;
                  }
		  log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
			     " MS-CHAP-Error \"%s\"\n", r->errstr);
                }
                break;

              case RAD_MICROSOFT_MS_CHAP2_SUCCESS:
                free(r->msrepstr);
                if (len == 0)
                  r->msrepstr = NULL;
                else {
                  if (len < 3 || ((const char *)data)[1] != '=') {
                    /*
                     * Only point at the String field if we don't think the
                     * peer has misformatted the response.
                     */
                    data = (const char *)data + 1;
                    len--;
                  } else
                    log_Printf(LogWARN, "Warning: The MS-CHAP2-Success "
                               "attribute is mis-formatted.  Compensating\n");
                  if ((r->msrepstr = rad_cvt_string((const char *)data,
                                                    len)) == NULL) {
                    log_Printf(LogERROR, "rad_cvt_string: %s\n",
                               rad_strerror(r->cx.rad));
                    auth_Failure(r->cx.auth);
                    rad_close(r->cx.rad);
                    return;
                  }
		  log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
			     " MS-CHAP2-Success \"%s\"\n", r->msrepstr);
                }
                break;

              case RAD_MICROSOFT_MS_MPPE_ENCRYPTION_POLICY:
                r->mppe.policy = rad_cvt_int(data);
		log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
			   " MS-MPPE-Encryption-Policy %s\n",
                           radius_policyname(r->mppe.policy));
                break;

              case RAD_MICROSOFT_MS_MPPE_ENCRYPTION_TYPES:
                r->mppe.types = rad_cvt_int(data);
		log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
			   " MS-MPPE-Encryption-Types %s\n",
                           radius_typesname(r->mppe.types));
                break;

              case RAD_MICROSOFT_MS_MPPE_RECV_KEY:
                free(r->mppe.recvkey);
		demangle(r, data, len, &r->mppe.recvkey, &r->mppe.recvkeylen);
		log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
			   " MS-MPPE-Recv-Key ********\n");
                break;

              case RAD_MICROSOFT_MS_MPPE_SEND_KEY:
		demangle(r, data, len, &r->mppe.sendkey, &r->mppe.sendkeylen);
		log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
			   " MS-MPPE-Send-Key ********\n");
                break;
#endif

              default:
                log_Printf(LogDEBUG, "Dropping MICROSOFT vendor specific "
                           "RADIUS attribute %d\n", res);
                break;
            }
            break;

          default:
            log_Printf(LogDEBUG, "Dropping vendor %lu RADIUS attribute %d\n",
                       (unsigned long)vendor, res);
            break;
        }
        break;

      default:
        log_Printf(LogDEBUG, "Dropping RADIUS attribute %d\n", res);
        break;
    }
  }

  if (res == -1) {
    log_Printf(LogERROR, "rad_get_attr: %s (failing!)\n",
               rad_strerror(r->cx.rad));
    auth_Failure(r->cx.auth);
  } else if (got == RAD_ACCESS_REJECT)
    auth_Failure(r->cx.auth);
  else {
    r->valid = 1;
    auth_Success(r->cx.auth);
  }
  rad_close(r->cx.rad);
}
Beispiel #8
0
static void
DoLoop(struct bundle *bundle)
{
  fd_set *rfds, *wfds, *efds;
  int i, nfds, nothing_done;

  if ((rfds = mkfdset()) == NULL) {
    log_Printf(LogERROR, "DoLoop: Cannot create fd_set\n");
    return;
  }

  if ((wfds = mkfdset()) == NULL) {
    log_Printf(LogERROR, "DoLoop: Cannot create fd_set\n");
    free(rfds);
    return;
  }

  if ((efds = mkfdset()) == NULL) {
    log_Printf(LogERROR, "DoLoop: Cannot create fd_set\n");
    free(rfds);
    free(wfds);
    return;
  }

  for (; !bundle_IsDead(bundle); bundle_CleanDatalinks(bundle)) {
    nfds = 0;
    zerofdset(rfds);
    zerofdset(wfds);
    zerofdset(efds);

    /* All our datalinks, the tun device and the MP socket */
    descriptor_UpdateSet(&bundle->desc, rfds, wfds, efds, &nfds);

    /* All our prompts and the diagnostic socket */
    descriptor_UpdateSet(&server.desc, rfds, NULL, NULL, &nfds);

    bundle_CleanDatalinks(bundle);
    if (bundle_IsDead(bundle))
      /* Don't select - we'll be here forever */
      break;

    /*
     * It's possible that we've had a signal since we last checked.  If
     * we don't check again before calling select(), we may end up stuck
     * after having missed the event.... sig_Handle() tries to be as
     * quick as possible if nothing is likely to have happened.
     * This is only really likely if we block in open(... O_NONBLOCK)
     * which will happen with a misconfigured device.
     */
    if (sig_Handle())
      continue;

    i = select(nfds, rfds, wfds, efds, NULL);

    if (i < 0 && errno != EINTR) {
      log_Printf(LogERROR, "DoLoop: select(): %s\n", strerror(errno));
      if (log_IsKept(LogTIMER)) {
        struct timeval t;

        for (i = 0; i <= nfds; i++) {
          if (FD_ISSET(i, rfds)) {
            log_Printf(LogTIMER, "Read set contains %d\n", i);
            FD_CLR(i, rfds);
            t.tv_sec = t.tv_usec = 0;
            if (select(nfds, rfds, wfds, efds, &t) != -1) {
              log_Printf(LogTIMER, "The culprit !\n");
              break;
            }
          }
          if (FD_ISSET(i, wfds)) {
            log_Printf(LogTIMER, "Write set contains %d\n", i);
            FD_CLR(i, wfds);
            t.tv_sec = t.tv_usec = 0;
            if (select(nfds, rfds, wfds, efds, &t) != -1) {
              log_Printf(LogTIMER, "The culprit !\n");
              break;
            }
          }
          if (FD_ISSET(i, efds)) {
            log_Printf(LogTIMER, "Error set contains %d\n", i);
            FD_CLR(i, efds);
            t.tv_sec = t.tv_usec = 0;
            if (select(nfds, rfds, wfds, efds, &t) != -1) {
              log_Printf(LogTIMER, "The culprit !\n");
              break;
            }
          }
        }
      }
      break;
    }

    log_Printf(LogTIMER, "Select returns %d\n", i);

    sig_Handle();

    if (i <= 0)
      continue;

    for (i = 0; i <= nfds; i++)
      if (FD_ISSET(i, efds)) {
        log_Printf(LogPHASE, "Exception detected on descriptor %d\n", i);
        /* We deal gracefully with link descriptor exceptions */
        if (!bundle_Exception(bundle, i)) {
          log_Printf(LogERROR, "Exception cannot be handled !\n");
          break;
        }
      }

    if (i <= nfds)
      break;

    nothing_done = 1;

    if (descriptor_IsSet(&server.desc, rfds)) {
      descriptor_Read(&server.desc, bundle, rfds);
      nothing_done = 0;
    }

    if (descriptor_IsSet(&bundle->desc, rfds)) {
      descriptor_Read(&bundle->desc, bundle, rfds);
      nothing_done = 0;
    }

    if (descriptor_IsSet(&bundle->desc, wfds))
      if (descriptor_Write(&bundle->desc, bundle, wfds) <= 0 && nothing_done) {
        /*
         * This is disastrous.  The OS has told us that something is
         * writable, and all our write()s have failed.  Rather than
         * going back immediately to do our UpdateSet()s and select(),
         * we sleep for a bit to avoid gobbling up all cpu time.
         */
        struct timeval t;

        t.tv_sec = 0;
        t.tv_usec = 100000;
        select(0, NULL, NULL, NULL, &t);
      }
  }

  log_Printf(LogDEBUG, "DoLoop done.\n");
}