diff options
Diffstat (limited to 'zebra/irdp_packet.c')
| -rw-r--r-- | zebra/irdp_packet.c | 550 | 
1 files changed, 272 insertions, 278 deletions
diff --git a/zebra/irdp_packet.c b/zebra/irdp_packet.c index 20982b31a1..3bd093d97b 100644 --- a/zebra/irdp_packet.c +++ b/zebra/irdp_packet.c @@ -20,14 +20,14 @@   * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA   */ -/*  +/*   * This work includes work with the following copywrite:   *   * Copyright (C) 1997, 2000 Kunihiro Ishiguro   *   */ -/*  +/*   * Thanks to Jens Låås at Swedish University of Agricultural Sciences   * for reviewing and tests.   */ @@ -71,294 +71,288 @@ int irdp_sock = -1;  extern struct thread *t_irdp_raw; -static void -parse_irdp_packet(char *p,  -		  int len,  -		  struct interface *ifp) +static void parse_irdp_packet(char *p, int len, struct interface *ifp)  { -  struct ip *ip = (struct ip *)p ; -  struct icmphdr *icmp; -  struct in_addr src; -  int ip_hlen, iplen, datalen; -  struct zebra_if *zi; -  struct irdp_interface *irdp; - -  zi = ifp->info; -  if (!zi)  -    return; - -  irdp = &zi->irdp; -  if (!irdp)  -    return; - -  ip_hlen = ip->ip_hl << 2; -   -  sockopt_iphdrincl_swab_systoh (ip); -   -  iplen = ip->ip_len; -  datalen = len - ip_hlen; -  src = ip->ip_src; - -  if (len != iplen) -    { -      zlog_err ("IRDP: RX length doesnt match IP length"); -      return; -    } - -  if (iplen < ICMP_MINLEN)  -    { -      zlog_err ("IRDP: RX ICMP packet too short from %s\n", -  	      inet_ntoa (src)); -      return; -    } -     -  /* XXX: RAW doesnt receive link-layer, surely? ??? */ -  /* Check so we don't checksum packets longer than oure RX_BUF - (ethlen + -   len of IP-header) 14+20 */ -  if (iplen > IRDP_RX_BUF-34)  -    { -      zlog_err ("IRDP: RX ICMP packet too long from %s\n", -	        inet_ntoa (src)); -      return; -    } - -  icmp = (struct icmphdr *) (p+ip_hlen); - -  /* check icmp checksum */     -  if (in_cksum (icmp, datalen) != icmp->checksum)  -    { -      zlog_warn ("IRDP: RX ICMP packet from %s. Bad checksum, silently ignored", -                 inet_ntoa (src)); -      return; -    } -   -  /* Handle just only IRDP */ -  if (!(icmp->type == ICMP_ROUTERADVERT -        || icmp->type == ICMP_ROUTERSOLICIT)) -    return; -   -  if (icmp->code != 0)  -    { -      zlog_warn ("IRDP: RX packet type %d from %s. Bad ICMP type code," -                 " silently ignored", -                 icmp->type, inet_ntoa (src)); -      return; -    } - -  if (! ((ntohl (ip->ip_dst.s_addr) == INADDR_BROADCAST) -         && (irdp->flags & IF_BROADCAST)) -        || -        (ntohl (ip->ip_dst.s_addr) == INADDR_ALLRTRS_GROUP -         && !(irdp->flags & IF_BROADCAST))) -    { -      zlog_warn ("IRDP: RX illegal from %s to %s while %s operates in %s\n", -                 inet_ntoa (src), -                 ntohl (ip->ip_dst.s_addr) == INADDR_ALLRTRS_GROUP ? -                 "multicast" : inet_ntoa (ip->ip_dst), -                 ifp->name, -                 irdp->flags & IF_BROADCAST ? "broadcast" : "multicast"); - -      zlog_warn ("IRDP: Please correct settings\n"); -      return; -    } - -  switch (icmp->type)  -    { -    case ICMP_ROUTERADVERT: -      break; - -    case ICMP_ROUTERSOLICIT: - -      if(irdp->flags & IF_DEBUG_MESSAGES)  -	zlog_debug ("IRDP: RX Solicit on %s from %s\n", -		    ifp->name, -		    inet_ntoa (src)); - -      process_solicit(ifp); -      break; - -    default: -      zlog_warn ("IRDP: RX type %d from %s. Bad ICMP type, silently ignored", -		 icmp->type, -		 inet_ntoa (src)); -    } +	struct ip *ip = (struct ip *)p; +	struct icmphdr *icmp; +	struct in_addr src; +	int ip_hlen, iplen, datalen; +	struct zebra_if *zi; +	struct irdp_interface *irdp; + +	zi = ifp->info; +	if (!zi) +		return; + +	irdp = &zi->irdp; +	if (!irdp) +		return; + +	ip_hlen = ip->ip_hl << 2; + +	sockopt_iphdrincl_swab_systoh(ip); + +	iplen = ip->ip_len; +	datalen = len - ip_hlen; +	src = ip->ip_src; + +	if (len != iplen) { +		zlog_err("IRDP: RX length doesnt match IP length"); +		return; +	} + +	if (iplen < ICMP_MINLEN) { +		zlog_err("IRDP: RX ICMP packet too short from %s\n", +			 inet_ntoa(src)); +		return; +	} + +	/* XXX: RAW doesnt receive link-layer, surely? ??? */ +	/* Check so we don't checksum packets longer than oure RX_BUF - (ethlen +	 + +	 len of IP-header) 14+20 */ +	if (iplen > IRDP_RX_BUF - 34) { +		zlog_err("IRDP: RX ICMP packet too long from %s\n", +			 inet_ntoa(src)); +		return; +	} + +	icmp = (struct icmphdr *)(p + ip_hlen); + +	/* check icmp checksum */ +	if (in_cksum(icmp, datalen) != icmp->checksum) { +		zlog_warn( +			"IRDP: RX ICMP packet from %s. Bad checksum, silently ignored", +			inet_ntoa(src)); +		return; +	} + +	/* Handle just only IRDP */ +	if (!(icmp->type == ICMP_ROUTERADVERT +	      || icmp->type == ICMP_ROUTERSOLICIT)) +		return; + +	if (icmp->code != 0) { +		zlog_warn( +			"IRDP: RX packet type %d from %s. Bad ICMP type code," +			" silently ignored", +			icmp->type, inet_ntoa(src)); +		return; +	} + +	if (!((ntohl(ip->ip_dst.s_addr) == INADDR_BROADCAST) +	      && (irdp->flags & IF_BROADCAST)) +	    || (ntohl(ip->ip_dst.s_addr) == INADDR_ALLRTRS_GROUP +		&& !(irdp->flags & IF_BROADCAST))) { +		zlog_warn( +			"IRDP: RX illegal from %s to %s while %s operates in %s\n", +			inet_ntoa(src), +			ntohl(ip->ip_dst.s_addr) == INADDR_ALLRTRS_GROUP +				? "multicast" +				: inet_ntoa(ip->ip_dst), +			ifp->name, +			irdp->flags & IF_BROADCAST ? "broadcast" : "multicast"); + +		zlog_warn("IRDP: Please correct settings\n"); +		return; +	} + +	switch (icmp->type) { +	case ICMP_ROUTERADVERT: +		break; + +	case ICMP_ROUTERSOLICIT: + +		if (irdp->flags & IF_DEBUG_MESSAGES) +			zlog_debug("IRDP: RX Solicit on %s from %s\n", +				   ifp->name, inet_ntoa(src)); + +		process_solicit(ifp); +		break; + +	default: +		zlog_warn( +			"IRDP: RX type %d from %s. Bad ICMP type, silently ignored", +			icmp->type, inet_ntoa(src)); +	}  } -static int -irdp_recvmsg (int sock, u_char *buf, int size, int *ifindex) +static int irdp_recvmsg(int sock, u_char *buf, int size, int *ifindex)  { -  struct msghdr msg; -  struct iovec iov; -  char adata[CMSG_SPACE( SOPT_SIZE_CMSG_PKTINFO_IPV4() )]; -  int ret; - -  msg.msg_name = (void *)0; -  msg.msg_namelen = 0; -  msg.msg_iov = &iov; -  msg.msg_iovlen = 1; -  msg.msg_control = (void *) adata; -  msg.msg_controllen = sizeof adata; - -  iov.iov_base = buf; -  iov.iov_len = size; - -  ret = recvmsg (sock, &msg, 0); -  if (ret < 0) { -    zlog_warn("IRDP: recvmsg: read error %s", safe_strerror(errno)); -    return ret; -  } - -  if (msg.msg_flags & MSG_TRUNC) { -    zlog_warn("IRDP: recvmsg: truncated message"); -    return ret; -  } -  if (msg.msg_flags & MSG_CTRUNC) { -    zlog_warn("IRDP: recvmsg: truncated control message"); -    return ret; -  } - -  *ifindex = getsockopt_ifindex (AF_INET, &msg); - -  return ret; +	struct msghdr msg; +	struct iovec iov; +	char adata[CMSG_SPACE(SOPT_SIZE_CMSG_PKTINFO_IPV4())]; +	int ret; + +	msg.msg_name = (void *)0; +	msg.msg_namelen = 0; +	msg.msg_iov = &iov; +	msg.msg_iovlen = 1; +	msg.msg_control = (void *)adata; +	msg.msg_controllen = sizeof adata; + +	iov.iov_base = buf; +	iov.iov_len = size; + +	ret = recvmsg(sock, &msg, 0); +	if (ret < 0) { +		zlog_warn("IRDP: recvmsg: read error %s", safe_strerror(errno)); +		return ret; +	} + +	if (msg.msg_flags & MSG_TRUNC) { +		zlog_warn("IRDP: recvmsg: truncated message"); +		return ret; +	} +	if (msg.msg_flags & MSG_CTRUNC) { +		zlog_warn("IRDP: recvmsg: truncated control message"); +		return ret; +	} + +	*ifindex = getsockopt_ifindex(AF_INET, &msg); + +	return ret;  }  int irdp_read_raw(struct thread *r)  { -  struct interface *ifp; -  struct zebra_if *zi; -  struct irdp_interface *irdp; -  char buf[IRDP_RX_BUF]; -  int ret, ifindex = 0; -   -  int irdp_sock = THREAD_FD (r); -  t_irdp_raw = NULL; -  thread_add_read(zebrad.master, irdp_read_raw, NULL, irdp_sock, &t_irdp_raw); -   -  ret = irdp_recvmsg (irdp_sock, (u_char *) buf, IRDP_RX_BUF,  &ifindex); -  -  if (ret < 0) zlog_warn ("IRDP: RX Error length = %d", ret); - -  ifp = if_lookup_by_index(ifindex, VRF_DEFAULT); -  if(! ifp ) return ret; - -  zi= ifp->info; -  if(! zi ) return ret; - -  irdp = &zi->irdp; -  if(! irdp ) return ret; - -  if(! (irdp->flags & IF_ACTIVE)) { - -    if(irdp->flags & IF_DEBUG_MISC)  -      zlog_debug("IRDP: RX ICMP for disabled interface %s\n", ifp->name); -    return 0; -  } - -  if(irdp->flags & IF_DEBUG_PACKET) { -    int i; -    zlog_debug("IRDP: RX (idx %d) ", ifindex); -    for(i=0; i < ret; i++) zlog_debug( "IRDP: RX %x ", buf[i]&0xFF); -  } - -  parse_irdp_packet(buf, ret, ifp); - -  return ret; +	struct interface *ifp; +	struct zebra_if *zi; +	struct irdp_interface *irdp; +	char buf[IRDP_RX_BUF]; +	int ret, ifindex = 0; + +	int irdp_sock = THREAD_FD(r); +	t_irdp_raw = NULL; +	thread_add_read(zebrad.master, irdp_read_raw, NULL, irdp_sock, +			&t_irdp_raw); + +	ret = irdp_recvmsg(irdp_sock, (u_char *)buf, IRDP_RX_BUF, &ifindex); + +	if (ret < 0) +		zlog_warn("IRDP: RX Error length = %d", ret); + +	ifp = if_lookup_by_index(ifindex, VRF_DEFAULT); +	if (!ifp) +		return ret; + +	zi = ifp->info; +	if (!zi) +		return ret; + +	irdp = &zi->irdp; +	if (!irdp) +		return ret; + +	if (!(irdp->flags & IF_ACTIVE)) { + +		if (irdp->flags & IF_DEBUG_MISC) +			zlog_debug("IRDP: RX ICMP for disabled interface %s\n", +				   ifp->name); +		return 0; +	} + +	if (irdp->flags & IF_DEBUG_PACKET) { +		int i; +		zlog_debug("IRDP: RX (idx %d) ", ifindex); +		for (i = 0; i < ret; i++) +			zlog_debug("IRDP: RX %x ", buf[i] & 0xFF); +	} + +	parse_irdp_packet(buf, ret, ifp); + +	return ret;  } -void  -send_packet(struct interface *ifp,  -	    struct stream *s, -	    u_int32_t dst, -	    struct prefix *p, -	    u_int32_t ttl) +void send_packet(struct interface *ifp, struct stream *s, u_int32_t dst, +		 struct prefix *p, u_int32_t ttl)  { -  static struct sockaddr_in sockdst = {AF_INET}; -  struct ip *ip; -  struct icmphdr *icmp; -  struct msghdr *msg; -  struct cmsghdr *cmsg; -  struct iovec iovector; -  char msgbuf[256]; -  char buf[256]; -  struct in_pktinfo *pktinfo; -  u_long src; -  u_char on; -  -  if (!(ifp->flags & IFF_UP)) -    return; - -  if (p) -    src = ntohl(p->u.prefix4.s_addr); -  else  -    src = 0; /* Is filled in */ -   -  ip = (struct ip *) buf; -  ip->ip_hl = sizeof(struct ip) >> 2; -  ip->ip_v = IPVERSION; -  ip->ip_tos = 0xC0; -  ip->ip_off = 0L; -  ip->ip_p = 1;       /* IP_ICMP */ -  ip->ip_ttl = ttl; -  ip->ip_src.s_addr = src; -  ip->ip_dst.s_addr = dst; -  icmp = (struct icmphdr *) (buf + sizeof (struct ip)); - -  /* Merge IP header with icmp packet */ -  assert (stream_get_endp(s) < (sizeof (buf) - sizeof (struct ip))); -  stream_get(icmp, s, stream_get_endp(s)); - -  /* icmp->checksum is already calculated */ -  ip->ip_len  = sizeof(struct ip) + stream_get_endp(s); - -  on = 1; -  if (setsockopt(irdp_sock, IPPROTO_IP, IP_HDRINCL, -		 (char *) &on, sizeof(on)) < 0) -    zlog_warn("sendto %s", safe_strerror (errno)); - - -  if(dst == INADDR_BROADCAST ) { -    on = 1; -    if (setsockopt(irdp_sock, SOL_SOCKET, SO_BROADCAST, -		   (char *) &on, sizeof(on)) < 0) -      zlog_warn("sendto %s", safe_strerror (errno)); -  } - -  if(dst !=  INADDR_BROADCAST) -    setsockopt_ipv4_multicast_loop (irdp_sock, 0); - -  memset(&sockdst,0,sizeof(sockdst)); -  sockdst.sin_family=AF_INET; -  sockdst.sin_addr.s_addr = dst; - -  cmsg = (struct cmsghdr *) (msgbuf + sizeof(struct msghdr)); -  cmsg->cmsg_len = sizeof(struct cmsghdr) + sizeof(struct in_pktinfo); -  cmsg->cmsg_level = SOL_IP; -  cmsg->cmsg_type = IP_PKTINFO; -  pktinfo = (struct in_pktinfo *) CMSG_DATA(cmsg); -  pktinfo->ipi_ifindex = ifp->ifindex; -  pktinfo->ipi_spec_dst.s_addr = src; -  pktinfo->ipi_addr.s_addr = src; -  -  iovector.iov_base = (void *) buf; -  iovector.iov_len = ip->ip_len;  -  msg = (struct msghdr *) msgbuf; -  msg->msg_name = &sockdst; -  msg->msg_namelen = sizeof(sockdst); -  msg->msg_iov = &iovector; -  msg->msg_iovlen = 1; -  msg->msg_control = cmsg; -  msg->msg_controllen = cmsg->cmsg_len; -  -  sockopt_iphdrincl_swab_htosys (ip); -   -  if (sendmsg(irdp_sock, msg, 0) < 0) { -    zlog_warn("sendto %s", safe_strerror (errno)); -  } -  /*   printf("TX on %s idx %d\n", ifp->name, ifp->ifindex); */ +	static struct sockaddr_in sockdst = {AF_INET}; +	struct ip *ip; +	struct icmphdr *icmp; +	struct msghdr *msg; +	struct cmsghdr *cmsg; +	struct iovec iovector; +	char msgbuf[256]; +	char buf[256]; +	struct in_pktinfo *pktinfo; +	u_long src; +	u_char on; + +	if (!(ifp->flags & IFF_UP)) +		return; + +	if (p) +		src = ntohl(p->u.prefix4.s_addr); +	else +		src = 0; /* Is filled in */ + +	ip = (struct ip *)buf; +	ip->ip_hl = sizeof(struct ip) >> 2; +	ip->ip_v = IPVERSION; +	ip->ip_tos = 0xC0; +	ip->ip_off = 0L; +	ip->ip_p = 1; /* IP_ICMP */ +	ip->ip_ttl = ttl; +	ip->ip_src.s_addr = src; +	ip->ip_dst.s_addr = dst; +	icmp = (struct icmphdr *)(buf + sizeof(struct ip)); + +	/* Merge IP header with icmp packet */ +	assert(stream_get_endp(s) < (sizeof(buf) - sizeof(struct ip))); +	stream_get(icmp, s, stream_get_endp(s)); + +	/* icmp->checksum is already calculated */ +	ip->ip_len = sizeof(struct ip) + stream_get_endp(s); + +	on = 1; +	if (setsockopt(irdp_sock, IPPROTO_IP, IP_HDRINCL, (char *)&on, +		       sizeof(on)) +	    < 0) +		zlog_warn("sendto %s", safe_strerror(errno)); + + +	if (dst == INADDR_BROADCAST) { +		on = 1; +		if (setsockopt(irdp_sock, SOL_SOCKET, SO_BROADCAST, (char *)&on, +			       sizeof(on)) +		    < 0) +			zlog_warn("sendto %s", safe_strerror(errno)); +	} + +	if (dst != INADDR_BROADCAST) +		setsockopt_ipv4_multicast_loop(irdp_sock, 0); + +	memset(&sockdst, 0, sizeof(sockdst)); +	sockdst.sin_family = AF_INET; +	sockdst.sin_addr.s_addr = dst; + +	cmsg = (struct cmsghdr *)(msgbuf + sizeof(struct msghdr)); +	cmsg->cmsg_len = sizeof(struct cmsghdr) + sizeof(struct in_pktinfo); +	cmsg->cmsg_level = SOL_IP; +	cmsg->cmsg_type = IP_PKTINFO; +	pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsg); +	pktinfo->ipi_ifindex = ifp->ifindex; +	pktinfo->ipi_spec_dst.s_addr = src; +	pktinfo->ipi_addr.s_addr = src; + +	iovector.iov_base = (void *)buf; +	iovector.iov_len = ip->ip_len; +	msg = (struct msghdr *)msgbuf; +	msg->msg_name = &sockdst; +	msg->msg_namelen = sizeof(sockdst); +	msg->msg_iov = &iovector; +	msg->msg_iovlen = 1; +	msg->msg_control = cmsg; +	msg->msg_controllen = cmsg->cmsg_len; + +	sockopt_iphdrincl_swab_htosys(ip); + +	if (sendmsg(irdp_sock, msg, 0) < 0) { +		zlog_warn("sendto %s", safe_strerror(errno)); +	} +	/*   printf("TX on %s idx %d\n", ifp->name, ifp->ifindex); */  }  #endif /* HAVE_IRDP */ - - -  | 
