⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 netlink.c

📁 BIRD的路由器守护程序源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
    case RTD_PROHIBIT:      break;    default:      return 0;    }  return 1;}static voidnl_send_route(struct krt_proto *p, rte *e, int new){  net *net = e->net;  rta *a = e->attrs;  struct {    struct nlmsghdr h;    struct rtmsg r;    char buf[128];  } r;  DBG("nl_send_route(%I/%d,new=%d)\n", net->n.prefix, net->n.pxlen, new);  bzero(&r.h, sizeof(r.h));  bzero(&r.r, sizeof(r.r));  r.h.nlmsg_type = new ? RTM_NEWROUTE : RTM_DELROUTE;  r.h.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));  r.h.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | (new ? NLM_F_CREATE|NLM_F_REPLACE : 0);  r.r.rtm_family = BIRD_AF;  r.r.rtm_dst_len = net->n.pxlen;  r.r.rtm_tos = 0;  r.r.rtm_table = KRT_CF->scan.table_id;  r.r.rtm_protocol = RTPROT_BIRD;  r.r.rtm_scope = RT_SCOPE_UNIVERSE;  nl_add_attr_ipa(&r.h, sizeof(r), RTA_DST, net->n.prefix);  switch (a->dest)    {    case RTD_ROUTER:      r.r.rtm_type = RTN_UNICAST;      nl_add_attr_ipa(&r.h, sizeof(r), RTA_GATEWAY, a->gw);      break;    case RTD_DEVICE:      if (!a->iface)	return;      r.r.rtm_type = RTN_UNICAST;      nl_add_attr_u32(&r.h, sizeof(r), RTA_OIF, a->iface->index);      break;    case RTD_BLACKHOLE:      r.r.rtm_type = RTN_BLACKHOLE;      break;    case RTD_UNREACHABLE:      r.r.rtm_type = RTN_UNREACHABLE;      break;    case RTD_PROHIBIT:      r.r.rtm_type = RTN_PROHIBIT;      break;    default:      bug("krt_capable inconsistent with nl_send_route");    }  nl_exchange(&r.h);}voidkrt_set_notify(struct krt_proto *p, net *n UNUSED, rte *new, rte *old){  if (old && new)    {      /*       *  We should check whether priority and TOS is identical as well,       *  but we don't use these and default value is always equal to default value. :-)       */      nl_send_route(p, new, 1);    }  else    {      if (old)	nl_send_route(p, old, 0);      if (new)	nl_send_route(p, new, 1);    }}static struct iface *krt_temp_iface(struct krt_proto *p, unsigned index){  struct iface *i, *j;  WALK_LIST(i, p->scan.temp_ifs)    if (i->index == index)      return i;  i = mb_allocz(p->p.pool, sizeof(struct iface));  if (j = if_find_by_index(index))    strcpy(i->name, j->name);  else    strcpy(i->name, "?");  i->index = index;  add_tail(&p->scan.temp_ifs, &i->n);  return i;}static voidnl_parse_route(struct nlmsghdr *h, int scan){  struct krt_proto *p;  struct rtmsg *i;  struct rtattr *a[RTA_CACHEINFO+1];  int new = h->nlmsg_type == RTM_NEWROUTE;  ip_addr dst;  rta ra;  rte *e;  net *net;  u32 oif;  int src;  if (!(i = nl_checkin(h, sizeof(*i))) || !nl_parse_attrs(RTM_RTA(i), a, sizeof(a)))    return;  if (i->rtm_family != BIRD_AF)    return;  if ((a[RTA_DST] && RTA_PAYLOAD(a[RTA_DST]) != sizeof(ip_addr)) ||      (a[RTA_OIF] && RTA_PAYLOAD(a[RTA_OIF]) != 4) ||      (a[RTA_PRIORITY] && RTA_PAYLOAD(a[RTA_PRIORITY]) != 4) ||#ifdef IPV6      (a[RTA_IIF] && RTA_PAYLOAD(a[RTA_IIF]) != 4) ||#endif      (a[RTA_GATEWAY] && RTA_PAYLOAD(a[RTA_GATEWAY]) != sizeof(ip_addr)))    {      log(L_ERR "nl_parse_route: Malformed message received");      return;    }  p = nl_table_map[i->rtm_table];	/* Do we know this table? */  if (!p)    return;#ifdef IPV6  if (a[RTA_IIF])    {      DBG("KRT: Ignoring route with IIF set\n");      return;    }#else  if (i->rtm_tos != 0)			/* We don't support TOS */    {      DBG("KRT: Ignoring route with TOS %02x\n", i->rtm_tos);      return;    }#endif  if (scan && !new)    {      DBG("KRT: Ignoring route deletion\n");      return;    }  if (a[RTA_DST])    {      memcpy(&dst, RTA_DATA(a[RTA_DST]), sizeof(dst));      ipa_ntoh(dst);    }  else    dst = IPA_NONE;  if (a[RTA_OIF])    memcpy(&oif, RTA_DATA(a[RTA_OIF]), sizeof(oif));  else    oif = ~0;  DBG("Got %I/%d, type=%d, oif=%d, table=%d, prid=%d, proto=%s\n", dst, i->rtm_dst_len, i->rtm_type, oif, i->rtm_table, i->rtm_protocol, p->p.name);  switch (i->rtm_protocol)    {    case RTPROT_REDIRECT:      src = KRT_SRC_REDIRECT;      break;    case RTPROT_KERNEL:      DBG("Route originated in kernel, ignoring\n");      return;    case RTPROT_BIRD:#ifdef IPV6    case RTPROT_BOOT:      /* Current Linux kernels don't remember rtm_protocol for IPv6 routes and supply RTPROT_BOOT instead */#endif      if (!scan)	{	  DBG("Echo of our own route, ignoring\n");	  return;	}      src = KRT_SRC_BIRD;      break;    default:      src = KRT_SRC_ALIEN;    }  net = net_get(p->p.table, dst, i->rtm_dst_len);  ra.proto = &p->p;  ra.source = RTS_INHERIT;  ra.scope = SCOPE_UNIVERSE;  ra.cast = RTC_UNICAST;  ra.flags = ra.aflags = 0;  ra.from = IPA_NONE;  ra.gw = IPA_NONE;  ra.iface = NULL;  ra.eattrs = NULL;  switch (i->rtm_type)    {    case RTN_UNICAST:      if (oif == ~0U)	{	  log(L_ERR "KRT: Mysterious route with no OIF (%I/%d)", net->n.prefix, net->n.pxlen);	  return;	}      if (a[RTA_GATEWAY])	{	  neighbor *ng;	  ra.dest = RTD_ROUTER;	  memcpy(&ra.gw, RTA_DATA(a[RTA_GATEWAY]), sizeof(ra.gw));	  ipa_ntoh(ra.gw);	  ng = neigh_find(&p->p, &ra.gw, 0);	  if (ng && ng->scope)	    ra.iface = ng->iface;	  else	    /* FIXME: Remove this warning? Handle it somehow... */	    log(L_WARN "Kernel told us to use non-neighbor %I for %I/%d", ra.gw, net->n.prefix, net->n.pxlen);	}      else	{	  ra.dest = RTD_DEVICE;	  ra.iface = krt_temp_iface(p, oif);	}      break;    case RTN_BLACKHOLE:      ra.dest = RTD_BLACKHOLE;      break;    case RTN_UNREACHABLE:      ra.dest = RTD_UNREACHABLE;      break;    case RTN_PROHIBIT:      ra.dest = RTD_PROHIBIT;      break;    /* FIXME: What about RTN_THROW? */    default:      DBG("KRT: Ignoring route with type=%d\n", i->rtm_type);      return;    }  if (i->rtm_scope != RT_SCOPE_UNIVERSE)    {      DBG("KRT: Ignoring route with scope=%d\n", i->rtm_scope);      return;    }  e = rte_get_temp(&ra);  e->net = net;  e->u.krt.src = src;  e->u.krt.proto = i->rtm_protocol;  e->u.krt.type = i->rtm_type;  if (a[RTA_PRIORITY])    memcpy(&e->u.krt.metric, RTA_DATA(a[RTA_PRIORITY]), sizeof(e->u.krt.metric));  else    e->u.krt.metric = 0;  if (scan)    krt_got_route(p, e);  else    krt_got_route_async(p, e, new);}voidkrt_scan_fire(struct krt_proto *p UNUSED)	/* CONFIG_ALL_TABLES_AT_ONCE => p is NULL */{  struct nlmsghdr *h;  nl_request_dump(RTM_GETROUTE);  while (h = nl_get_scan())    if (h->nlmsg_type == RTM_NEWROUTE || h->nlmsg_type == RTM_DELROUTE)      nl_parse_route(h, 1);    else      log(L_DEBUG "nl_scan_fire: Unknown packet received (type=%d)", h->nlmsg_type);}/* *	Asynchronous Netlink interface */static sock *nl_async_sk;		/* BIRD socket for asynchronous notifications */static byte *nl_async_rx_buffer;	/* Receive buffer */static voidnl_async_msg(struct nlmsghdr *h){  switch (h->nlmsg_type)    {    case RTM_NEWROUTE:    case RTM_DELROUTE:      DBG("KRT: Received async route notification (%d)\n", h->nlmsg_type);      nl_parse_route(h, 0);      break;    case RTM_NEWLINK:    case RTM_DELLINK:      DBG("KRT: Received async link notification (%d)\n", h->nlmsg_type);      nl_parse_link(h, 0);      break;    case RTM_NEWADDR:    case RTM_DELADDR:      DBG("KRT: Received async address notification (%d)\n", h->nlmsg_type);      nl_parse_addr(h);      break;    default:      DBG("KRT: Received unknown async notification (%d)\n", h->nlmsg_type);    }}static intnl_async_hook(sock *sk, int size UNUSED){  struct iovec iov = { nl_async_rx_buffer, NL_RX_SIZE };  struct sockaddr_nl sa;  struct msghdr m = { (struct sockaddr *) &sa, sizeof(sa), &iov, 1, NULL, 0, 0 };  struct nlmsghdr *h;  int x;  unsigned int len;  nl_last_hdr = NULL;		/* Discard packets accidentally remaining in the rxbuf */  x = recvmsg(sk->fd, &m, 0);  if (x < 0)    {      if (errno == ENOBUFS)	{	  /*	   *  Netlink reports some packets have been thrown away.	   *  One day we might react to it by asking for route table	   *  scan in near future.	   */	  return 1;	/* More data are likely to be ready */	}      else if (errno != EWOULDBLOCK)	log(L_ERR "Netlink recvmsg: %m");      return 0;    }  if (sa.nl_pid)		/* It isn't from the kernel */    {      DBG("Non-kernel packet\n");      return 1;    }  h = (void *) nl_async_rx_buffer;  len = x;  if (m.msg_flags & MSG_TRUNC)    {      log(L_WARN "Netlink got truncated asynchronous message");      return 1;    }  while (NLMSG_OK(h, len))    {      nl_async_msg(h);      h = NLMSG_NEXT(h, len);    }  if (len)    log(L_WARN "nl_async_hook: Found packet remnant of size %d", len);  return 1;}static voidnl_open_async(void){  sock *sk;  struct sockaddr_nl sa;  int fd;  static int nl_open_tried = 0;  if (nl_open_tried)    return;  nl_open_tried = 1;  DBG("KRT: Opening async netlink socket\n");  fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);  if (fd < 0)    {      log(L_ERR "Unable to open asynchronous rtnetlink socket: %m");      return;    }  bzero(&sa, sizeof(sa));  sa.nl_family = AF_NETLINK;#ifdef IPV6  sa.nl_groups = RTMGRP_LINK | RTMGRP_IPV6_IFADDR | RTMGRP_IPV6_ROUTE;#else  sa.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE;#endif  if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0)    {      log(L_ERR "Unable to bind asynchronous rtnetlink socket: %m");      return;    }  sk = nl_async_sk = sk_new(krt_pool);  sk->type = SK_MAGIC;  sk->rx_hook = nl_async_hook;  sk->fd = fd;  if (sk_open(sk))    bug("Netlink: sk_open failed");  if (!nl_async_rx_buffer)    nl_async_rx_buffer = xmalloc(NL_RX_SIZE);}/* *	Interface to the UNIX krt module */static u8 nl_cf_table[(NL_NUM_TABLES+7) / 8];voidkrt_scan_preconfig(struct config *c UNUSED){  bzero(&nl_cf_table, sizeof(nl_cf_table));}voidkrt_scan_postconfig(struct krt_config *x){  int id = x->scan.table_id;  if (nl_cf_table[id/8] & (1 << (id%8)))    cf_error("Multiple kernel syncers defined for table #%d", id);  nl_cf_table[id/8] |= (1 << (id%8));}voidkrt_scan_construct(struct krt_config *x){#ifndef IPV6  x->scan.table_id = RT_TABLE_MAIN;#else  x->scan.table_id = 254;#endif}voidkrt_scan_start(struct krt_proto *p, int first){  init_list(&p->scan.temp_ifs);  nl_table_map[KRT_CF->scan.table_id] = p;  if (first)    {      nl_open();      nl_open_async();    }}voidkrt_scan_shutdown(struct krt_proto *p UNUSED, int last UNUSED){}voidkrt_if_start(struct kif_proto *p UNUSED){  nl_open();  nl_open_async();}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -