Example #1
0
static void
scan_ifs(struct ifreq *r, int cnt)
{
  struct iface i, *pi;
  struct ifa a;
  char *err, *colon;
  unsigned fl;
  ip_addr netmask;
  int l, scope;
  sockaddr *sa;

  if_start_update();
  for (cnt /= sizeof(struct ifreq); cnt; cnt--, r++)
    {
      int sec = 0;
      bzero(&i, sizeof(i));
      bzero(&a, sizeof(a));
      if (colon = strchr(r->ifr_name, ':'))
	{
	  /* It's an alias -- let's interpret it as a secondary interface address */
	  sec = 1;
	  *colon = 0;
	}
      strncpy(i.name, r->ifr_name, sizeof(i.name) - 1);

      if(ioctl(if_scan_sock, SIOCGIFADDR,r)<0) continue;

      get_sockaddr((struct sockaddr_in *) &r->ifr_addr, &a.ip, NULL, 1);
      if (ipa_nonzero(a.ip))
	{
	  l = ipa_classify(a.ip);
	  if (l < 0 || !(l & IADDR_HOST))
	    {
	      log(L_ERR "%s: Invalid interface address", i.name);
	      a.ip = IPA_NONE;
	    }
	  else
	    {
	      a.scope = l & IADDR_SCOPE_MASK;
	      if (a.scope == SCOPE_HOST)
		i.flags |= IF_LOOPBACK | IF_IGNORE;
	    }
	}

      if (ioctl(if_scan_sock, SIOCGIFFLAGS, r) < 0)
	{
	  err = "SIOCGIFFLAGS";
	faulty:
	  log(L_ERR "%s(%s): %m", err, i.name);
	bad:
	  i.flags = (i.flags & ~IF_LINK_UP) | IF_ADMIN_DOWN;
	  continue;
	}
      fl = r->ifr_flags;
      if (fl & IFF_UP)
	i.flags |= IF_LINK_UP;

      if (ioctl(if_scan_sock, SIOCGIFNETMASK, r) < 0)
	{ err = "SIOCGIFNETMASK"; goto faulty; }
      get_sockaddr((struct sockaddr_in *) &r->ifr_addr, &netmask, NULL, 0);
      l = ipa_mklen(netmask);
      if (l < 0 || l == 31)
	{
	  log(L_ERR "%s: Invalid netmask (%x)", i.name, netmask);
	  goto bad;
	}
      a.pxlen = l;

      if (fl & IFF_POINTOPOINT)
	{
	  a.flags |= IA_UNNUMBERED;
	  if (ioctl(if_scan_sock, SIOCGIFDSTADDR, r) < 0)
	    { err = "SIOCGIFDSTADDR"; goto faulty; }
	  get_sockaddr((struct sockaddr_in *) &r->ifr_addr, &a.opposite, NULL, 1);
	  a.prefix = a.opposite;
	  a.pxlen = BITS_PER_IP_ADDRESS;
	}
      else
	a.prefix = ipa_and(a.ip, ipa_mkmask(a.pxlen));
      if (fl & IFF_LOOPBACK)
	i.flags |= IF_LOOPBACK | IF_IGNORE;
      if (1
#ifndef CONFIG_ALL_MULTICAST
	  && (fl & IFF_MULTICAST)
#endif
#ifndef CONFIG_UNNUM_MULTICAST
	  && !(a.flags & IA_UNNUMBERED)
#endif
	 )
	i.flags |= IF_MULTICAST;

      scope = ipa_classify(a.ip);
      if (scope < 0)
	{
	  log(L_ERR "%s: Invalid address", i.name);
	  goto bad;
	}
      a.scope = scope & IADDR_SCOPE_MASK;

      if (a.pxlen < 32)
	{
	  a.brd = ipa_or(a.prefix, ipa_not(ipa_mkmask(a.pxlen)));
	  if (ipa_equal(a.ip, a.prefix) || ipa_equal(a.ip, a.brd))
	    {
	      log(L_ERR "%s: Using network or broadcast address for interface", i.name);
	      goto bad;
	    }
	  if (fl & IFF_BROADCAST)
	    i.flags |= IF_BROADCAST;
	  if (a.pxlen < 30)
	    i.flags |= IF_MULTIACCESS;
	  else
	    a.opposite = ipa_opposite(a.ip, a.pxlen);
	}
      else
	a.brd = a.opposite;
      a.scope = SCOPE_UNIVERSE;

      if (ioctl(if_scan_sock, SIOCGIFMTU, r) < 0)
	{ err = "SIOCGIFMTU"; goto faulty; }
      i.mtu = r->ifr_mtu;

#ifdef SIOCGIFINDEX
      if (ioctl(if_scan_sock, SIOCGIFINDEX, r) >= 0)
	i.index = r->ifr_ifindex;
      else if (errno != EINVAL)
	DBG("SIOCGIFINDEX failed: %m\n");
      else	/* defined, but not supported by the kernel */
#endif
      /*
       *  The kernel doesn't give us real ifindices, but we still need them
       *  at least for OSPF unnumbered links. So let's make them up ourselves.
       */
      if (pi = if_find_by_name(i.name))
	i.index = pi->index;
      else
	{
	  static int if_index_counter = 1;
	  i.index = if_index_counter++;
	}

      pi = NULL;
      if (sec)
	{
	  a.flags |= IA_SECONDARY;
	  pi = if_find_by_index(i.index);
	}
      if (!pi)
	pi = if_update(&i);
      a.iface = pi;
      ifa_update(&a);
    }
  if_end_update();
}
Example #2
0
static void
krt_parse_entry(byte *ent, struct krt_proto *p)
{
  u32 dest0, gw0, mask0;
  ip_addr dest, gw, mask;
  unsigned int flags;
  int masklen;
  net *net;
  byte *iface = ent;
  rte *e;

  if (sscanf(ent, "%*s\t%x\t%x\t%x\t%*d\t%*d\t%*d\t%x\t", &dest0, &gw0, &flags, &mask0) != 4)
    {
      log(L_ERR "krt read: unable to parse `%s'", ent);
      return;
    }
  while (*ent != '\t')
    ent++;
  *ent = 0;

  dest = ipa_from_u32(dest0);
  ipa_ntoh(dest);
  gw = ipa_from_u32(gw0);
  ipa_ntoh(gw);
  mask = ipa_from_u32(mask0);
  ipa_ntoh(mask);
  if ((masklen = ipa_mklen(mask)) < 0)
    {
      log(L_ERR "krt read: invalid netmask %08x", mask0);
      return;
    }
  DBG("Got %I/%d via %I flags %x\n", dest, masklen, gw, flags);

  if (!(flags & RTF_UP))
    {
      DBG("Down.\n");
      return;
    }
  if (flags & RTF_HOST)
    masklen = 32;
  if (flags & (RTF_DYNAMIC | RTF_MODIFIED)) /* Redirect route */
    {
      log(L_WARN "krt: Ignoring redirect to %I/%d via %I", dest, masklen, gw);
      return;
    }

  net = net_get(p->p.table, dest, masklen);

  rta a = {
    .proto = &p->p,
    .source = RTS_INHERIT,
    .scope = SCOPE_UNIVERSE,
    .cast = RTC_UNICAST
  };

  if (flags & RTF_GATEWAY)
    {
      neighbor *ng = neigh_find(&p->p, &gw, 0);
      if (ng && ng->scope)
	a.iface = ng->iface;
      else
	{
	  log(L_WARN "Kernel told us to use non-neighbor %I for %I/%d", gw, net->n.prefix, net->n.pxlen);
	  return;
	}
      a.dest = RTD_ROUTER;
      a.gw = gw;
    }
  else if (flags & RTF_REJECT)
    {
      a.dest = RTD_UNREACHABLE;
      a.gw = IPA_NONE;
    }
  else if (isalpha(iface[0]))
    {
      a.dest = RTD_DEVICE;
      a.gw = IPA_NONE;
      a.iface = krt_temp_iface(p, iface);
    }
  else
    {
      log(L_WARN "Kernel reporting unknown route type to %I/%d", net->n.prefix, net->n.pxlen);
      return;
    }

  e = rte_get_temp(&a);
  e->net = net;
  e->u.krt.src = KRT_SRC_UNKNOWN;
  krt_got_route(p, e);
}

void
krt_scan_fire(struct krt_proto *p)
{
  byte buf[32768];
  int l, seen_hdr;

  if (krt_scan_fd < 0)
    {
      krt_scan_fd = open("/proc/net/route", O_RDONLY);
      if (krt_scan_fd < 0)
	die("/proc/net/route: %m");
    }
  else if (lseek(krt_scan_fd, 0, SEEK_SET) < 0)
    {
      log(L_ERR "krt seek: %m");
      return;
    }
  seen_hdr = 0;
  while ((l = read(krt_scan_fd, buf, sizeof(buf))) > 0)
    {
      byte *z = buf;
      if (l & 127)
	{
	  log(L_ERR "krt read: misaligned entry: l=%d", l);
	  return;
	}
      while (l >= 128)
	{
	  if (seen_hdr++)
	    krt_parse_entry(z, p);
	  z += 128;
	  l -= 128;
	}
    }
  if (l < 0)
    {
      log(L_ERR "krt read: %m");
      return;
    }
  DBG("KRT scan done, seen %d lines\n", seen_hdr);
}