📄 ospf_packet.c
字号:
struct msghdr msgh = {NULL, 0, &iov, 1, buff, sizeof (*cmsg) + sizeof (*pktinfo), 0}; ret = recvfrom (fd, (void *)&iph, sizeof (iph), MSG_PEEK, NULL, 0); if (ret != sizeof (iph)) { zlog_warn ("ospf_recv_packet packet smaller than ip header"); return NULL; }#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) ip_len = iph.ip_len;#else ip_len = ntohs (iph.ip_len);#endif#if !defined(GNU_LINUX) /* * Kernel network code touches incoming IP header parameters, * before protocol specific processing. * * 1) Convert byteorder to host representation. * --> ip_len, ip_id, ip_off * * 2) Adjust ip_len to strip IP header size! * --> If user process receives entire IP packet via RAW * socket, it must consider adding IP header size to * the "ip_len" field of "ip" structure. * * For more details, see <netinet/ip_input.c>. */ ip_len = ip_len + (iph.ip_hl << 2);#endif ibuf = stream_new (ip_len); iov.iov_base = STREAM_DATA (ibuf); iov.iov_len = ip_len; ret = recvmsg (fd, &msgh, 0); cmsg = CMSG_FIRSTHDR (&msgh); if (cmsg != NULL && //cmsg->cmsg_len == sizeof (*pktinfo) && cmsg->cmsg_level == IPPROTO_IP &&#if defined (IP_PKTINFO) cmsg->cmsg_type == IP_PKTINFO#elif defined (IP_RECVIF) cmsg->cmsg_type == IP_RECVIF#else 0#endif ) {#if defined (IP_PKTINFO) pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsg); ifindex = pktinfo->ipi_ifindex;#elif defined (IP_RECVIF) pktinfo = (struct sockaddr_dl *)CMSG_DATA(cmsg); ifindex = pktinfo->sdl_index;#else ifindex = 0;#endif } *ifp = if_lookup_by_index (ifindex); if (ret != ip_len) { zlog_warn ("ospf_recv_packet short read. " "ip_len %d bytes read %d", ip_len, ret); stream_free (ibuf); return NULL; } return ibuf;}struct ospf_interface *ospf_associate_packet_vl (struct ospf *ospf, struct interface *ifp, struct ospf_interface *oi, struct ip *iph, struct ospf_header *ospfh){ struct ospf_interface *rcv_oi; struct ospf_vl_data *vl_data; struct ospf_area *vl_area; listnode node; if (IN_MULTICAST (ntohl (iph->ip_dst.s_addr)) || !OSPF_IS_AREA_BACKBONE (ospfh)) return oi; if ((rcv_oi = oi) == NULL) { if ((rcv_oi = ospf_if_lookup_by_local_addr (ospf, ifp, iph->ip_dst)) == NULL) return NULL; } for (node = listhead (ospf->vlinks); node; nextnode (node)) { if ((vl_data = getdata (node)) == NULL) continue; vl_area = ospf_area_lookup_by_area_id (ospf, vl_data->vl_area_id); if (!vl_area) continue; if (OSPF_AREA_SAME (&vl_area, &rcv_oi->area) && IPV4_ADDR_SAME (&vl_data->vl_peer, &ospfh->router_id)) { if (IS_DEBUG_OSPF_EVENT) zlog_info ("associating packet with %s", IF_NAME (vl_data->vl_oi)); if (! CHECK_FLAG (vl_data->vl_oi->ifp->flags, IFF_UP)) { if (IS_DEBUG_OSPF_EVENT) zlog_info ("This VL is not up yet, sorry"); return NULL; } return vl_data->vl_oi; } } if (IS_DEBUG_OSPF_EVENT) zlog_info ("couldn't find any VL to associate the packet with"); return oi;}intospf_check_area_id (struct ospf_interface *oi, struct ospf_header *ospfh){ /* Check match the Area ID of the receiving interface. */ if (OSPF_AREA_SAME (&oi->area, &ospfh)) return 1; return 0;}/* Unbound socket will accept any Raw IP packets if proto is matched. To prevent it, compare src IP address and i/f address with masking i/f network mask. */intospf_check_network_mask (struct ospf_interface *oi, struct in_addr ip_src){ struct in_addr mask, me, him; if (oi->type == OSPF_IFTYPE_POINTOPOINT || oi->type == OSPF_IFTYPE_VIRTUALLINK) return 1; masklen2ip (oi->address->prefixlen, &mask); me.s_addr = oi->address->u.prefix4.s_addr & mask.s_addr; him.s_addr = ip_src.s_addr & mask.s_addr; if (IPV4_ADDR_SAME (&me, &him)) return 1; return 0;}intospf_check_auth (struct ospf_interface *oi, struct stream *ibuf, struct ospf_header *ospfh){ int ret = 0; struct crypt_key *ck; switch (ntohs (ospfh->auth_type)) { case OSPF_AUTH_NULL: ret = 1; break; case OSPF_AUTH_SIMPLE: if (!memcmp (OSPF_IF_PARAM (oi, auth_simple), ospfh->u.auth_data, OSPF_AUTH_SIMPLE_SIZE)) ret = 1; else ret = 0; break; case OSPF_AUTH_CRYPTOGRAPHIC: if ((ck = getdata (OSPF_IF_PARAM (oi,auth_crypt)->tail)) == NULL) { ret = 0; break; } /* This is very basic, the digest processing is elsewhere */ if (ospfh->u.crypt.auth_data_len == OSPF_AUTH_MD5_SIZE && ospfh->u.crypt.key_id == ck->key_id && ntohs (ospfh->length) + OSPF_AUTH_SIMPLE_SIZE <= stream_get_size (ibuf)) ret = 1; else ret = 0; break; default: ret = 0; break; } return ret;}intospf_check_sum (struct ospf_header *ospfh){ u_int32_t ret; u_int16_t sum; int in_cksum (void *ptr, int nbytes); /* clear auth_data for checksum. */ memset (ospfh->u.auth_data, 0, OSPF_AUTH_SIMPLE_SIZE); /* keep checksum and clear. */ sum = ospfh->checksum; memset (&ospfh->checksum, 0, sizeof (u_int16_t)); /* calculate checksum. */ ret = in_cksum (ospfh, ntohs (ospfh->length)); if (ret != sum) { zlog_info ("ospf_check_sum(): checksum mismatch, my %X, his %X", ret, sum); return 0; } return 1;}/* OSPF Header verification. */intospf_verify_header (struct stream *ibuf, struct ospf_interface *oi, struct ip *iph, struct ospf_header *ospfh){ /* check version. */ if (ospfh->version != OSPF_VERSION) { zlog_warn ("interface %s: ospf_read version number mismatch.", IF_NAME (oi)); return -1; } /* Check Area ID. */ if (!ospf_check_area_id (oi, ospfh)) { zlog_warn ("interface %s: ospf_read invalid Area ID %s.", IF_NAME (oi), inet_ntoa (ospfh->area_id)); return -1; } /* Check network mask, Silently discarded. */ if (! ospf_check_network_mask (oi, iph->ip_src)) { zlog_warn ("interface %s: ospf_read network address is not same [%s]", IF_NAME (oi), inet_ntoa (iph->ip_src)); return -1; } /* Check authentication. */ if (ospf_auth_type (oi) != ntohs (ospfh->auth_type)) { zlog_warn ("interface %s: ospf_read authentication type mismatch.", IF_NAME (oi)); return -1; } if (! ospf_check_auth (oi, ibuf, ospfh)) { zlog_warn ("interface %s: ospf_read authentication failed.", IF_NAME (oi)); return -1; } /* if check sum is invalid, packet is discarded. */ if (ntohs (ospfh->auth_type) != OSPF_AUTH_CRYPTOGRAPHIC) { if (! ospf_check_sum (ospfh)) { zlog_warn ("interface %s: ospf_read packet checksum error %s", IF_NAME (oi), inet_ntoa (ospfh->router_id)); return -1; } } else { if (ospfh->checksum != 0) return -1; if (ospf_check_md5_digest (oi, ibuf, ntohs (ospfh->length)) == 0) { zlog_warn ("interface %s: ospf_read md5 authentication failed.", IF_NAME (oi)); return -1; } } return 0;}/* Starting point of packet process function. */intospf_read (struct thread *thread){ int ret; struct stream *ibuf; struct ospf *ospf; struct ospf_interface *oi; struct ip *iph; struct ospf_header *ospfh; u_int16_t length; struct interface *ifp; /* first of all get interface pointer. */ ospf = THREAD_ARG (thread); ospf->t_read = NULL; /* read OSPF packet. */ ibuf = ospf_recv_packet (ospf->fd, &ifp); if (ibuf == NULL) return -1; iph = (struct ip *) STREAM_DATA (ibuf); /* prepare for next packet. */ ospf->t_read = thread_add_read (master, ospf_read, ospf, ospf->fd); /* IP Header dump. */ /* if (ospf_debug_packet & OSPF_DEBUG_RECV) ospf_ip_header_dump (ibuf); */ /* Self-originated packet should be discarded silently. */ if (ospf_if_lookup_by_local_addr (ospf, NULL, iph->ip_src)) { stream_free (ibuf); return 0; } /* Adjust size to message length. */ stream_forward (ibuf, iph->ip_hl * 4); /* Get ospf packet header. */ ospfh = (struct ospf_header *) STREAM_PNT (ibuf); /* associate packet with ospf interface */ oi = ospf_if_lookup_recv_if (ospf, iph->ip_src); if (ifp && oi && oi->ifp != ifp) { zlog_warn ("Packet from [%s] received on wrong link %s", inet_ntoa (iph->ip_src), ifp->name); stream_free (ibuf); return 0; } if ((oi = ospf_associate_packet_vl (ospf, ifp, oi, iph, ospfh)) == NULL) { stream_free (ibuf); return 0; } /* * If the received packet is destined for AllDRouters, the packet * should be accepted only if the received ospf interface state is * either DR or Backup -- endo. */ if (iph->ip_dst.s_addr == htonl (OSPF_ALLDROUTERS) && (oi->state != ISM_DR && oi->state != ISM_Backup)) { zlog_info ("Packet for AllDRouters from [%s] via [%s] (ISM: %s)", inet_ntoa (iph->ip_src), IF_NAME (oi), LOOKUP (ospf_ism_state_msg, oi->state)); stream_free (ibuf); return 0; } /* Show debug receiving packet. */ if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, RECV)) { if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, DETAIL)) { zlog_info ("-----------------------------------------------------"); ospf_packet_dump (ibuf); } zlog_info ("%s received from [%s] via [%s]", ospf_packet_type_str[ospfh->type], inet_ntoa (ospfh->router_id), IF_NAME (oi)); zlog_info (" src [%s],", inet_ntoa (iph->ip_src)); zlog_info (" dst [%s]", inet_ntoa (iph->ip_dst)); if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, DETAIL)) zlog_info ("-----------------------------------------------------"); } /* Some header verification. */ ret = ospf_verify_header (ibuf, oi, iph, ospfh); if (ret < 0) { stream_free (ibuf); return ret; } stream_forward (ibuf, OSPF_HEADER_SIZE); /* Adjust size to message length. */ length = ntohs (ospfh->length) - OSPF_HEADER_SIZE; /* Read rest of the packet and call each sort of packet routine. */ switch (ospfh->type) { case OSPF_MSG_HELLO: ospf_hello (iph, ospfh, ibuf, oi, length); break; case OSPF_MSG_DB_DESC: ospf_db_desc (iph, ospfh, ibuf, oi, length); break; case OSPF_MSG_LS_REQ: ospf_ls_req (iph, ospfh, ibuf, oi, length); break; case OSPF_MSG_LS_UPD: ospf_ls_upd (iph, ospfh, ibuf, oi, length); break; case OSPF_MSG_LS_ACK: ospf_ls_ack (iph, ospfh, ibuf, oi, length); break; default: zlog (NULL, LOG_WARNING, "interface %s: OSPF packet header type %d is illegal", IF_NAME (oi), ospfh->type); break; } stream_free (ibuf); return 0;}/* Make OSPF header. */voidospf_make_header (int type, struct ospf_interface *oi, struct stream *s){ struct ospf_header *ospfh; ospfh = (struct ospf_header *) STREAM_DATA (s); ospfh->version = (u_char) OSPF_VERSION; ospfh->type = (u_char) type; ospfh->router_id = oi->ospf->router_id; ospfh->checksum = 0; ospfh->area_id = oi->area->area_id; ospfh->auth_type = htons (ospf_auth_type (oi)); memset (ospfh->u.auth_data, 0, OSPF_AUTH_SIMPLE_SIZE); ospf_output_forward (s, OSPF_HEADER_SIZE);}/* Make Authentication Data. */intospf_make_auth (struct ospf_interface *oi, struct ospf_header *ospfh){ struct crypt_key *ck; switch (ospf_auth_type (oi)) { case OSPF_AUTH_NULL: /* memset (ospfh->u.auth_data, 0, sizeof (ospfh->u.auth_data)); */ break; case OSPF_AUTH
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -