/* ------------------------------------------------------------------- * Listens for connections and starts Servers to handle data. * For TCP, each accepted connection spawns a Server thread. * For UDP, handle all data in this thread for Win32 Only, otherwise * spawn a new Server thread. * ------------------------------------------------------------------- */ void Listener::Run( void ) { #ifdef WIN32 if ( isUDP( mSettings ) && !isSingleUDP( mSettings ) ) { UDPSingleServer(); } else #else #ifdef sun if ( ( isUDP( mSettings ) && isMulticast( mSettings ) && !isSingleUDP( mSettings ) ) || isSingleUDP( mSettings ) ) { UDPSingleServer(); } else #else if ( isSingleUDP( mSettings ) ) { UDPSingleServer(); } else
bool Discovery::initMulticast(int port) { const char *mcastaddr = "ff02::1"; // "FF01:0:0:0:0:0:0:1"; // all nodes // "FF01::1111"; //const char *mcastaddr = "FF01:0:0:0:0:0:0:1"; //const char *mcastaddr = "FF01::1111"; memset(&m_multicastAddrBind, 0, sizeof(m_multicastAddrBind)); memset(&m_multicastAddrSend, 0, sizeof(m_multicastAddrSend)); if (get_multicast_addrs(mcastaddr, std::to_string(port).c_str(), SOCK_DGRAM, &m_multicastAddrBind, &m_multicastAddrSend) <0) { LOG(logERROR) << "get_addr error:: could not find multicast " << "address=[" << mcastaddr << "] port=[" << port << " ]"; return false; } if (!isMulticast(&m_multicastAddrSend)) { LOG(logERROR) << "This address does not seem a multicast address " << m_multicastAddrSend; return false; } m_socMulticast = socket(m_multicastAddrBind.ss_family, SOCK_DGRAM, 0); if (!socketSetBlocking(m_socMulticast, false)) return false; /*if (bind(m_socMulticast, (struct sockaddr *)&m_multicastAddrBind, sizeof(m_multicastAddrBind)) < 0) { LOG(logERROR) << "bind error on port " << port; return false; } LOG(logDEBUG) << "bound multicast socket to " << m_multicastAddrBind; */ if (joinGroup(m_socMulticast, 0, 8, &m_multicastAddrSend) <0) { LOG(logERROR) << "failed to join multicast group!"; return false; } return true; }
void Client::Run( void ) { struct UDP_datagram* mBuf_UDP = (struct UDP_datagram*) mBuf; unsigned long currLen = 0; int delay_target = 0; int delay = 0; int adjust = 0; char* readAt = mBuf; #if HAVE_THREAD if ( !isUDP( mSettings ) ) { RunTCP(); return; } #endif // Indicates if the stream is readable bool canRead = true, mMode_Time = isModeTime( mSettings ); // setup termination variables if ( mMode_Time ) { mEndTime.setnow(); mEndTime.add( mSettings->mAmount / 100.0 ); } if ( isUDP( mSettings ) ) { // Due to the UDP timestamps etc, included // reduce the read size by an amount // equal to the header size // compute delay for bandwidth restriction, constrained to [0,1] seconds delay_target = (int) ( mSettings->mBufLen * ((kSecs_to_usecs * kBytes_to_Bits) / mSettings->mUDPRate) ); if ( delay_target < 0 || delay_target > (int) 1 * kSecs_to_usecs ) { fprintf( stderr, warn_delay_large, delay_target / kSecs_to_usecs ); delay_target = (int) kSecs_to_usecs * 1; } if ( isFileInput( mSettings ) ) { if ( isCompat( mSettings ) ) { Extractor_reduceReadSize( sizeof(struct UDP_datagram), mSettings ); readAt += sizeof(struct UDP_datagram); } else { Extractor_reduceReadSize( sizeof(struct UDP_datagram) + sizeof(struct client_hdr), mSettings ); readAt += sizeof(struct UDP_datagram) + sizeof(struct client_hdr); } } } ReportStruct *reportstruct = NULL; // InitReport handles Barrier for multiple Streams mSettings->reporthdr = InitReport( mSettings ); reportstruct = new ReportStruct; reportstruct->packetID = 0; lastPacketTime.setnow(); do { // Test case: drop 17 packets and send 2 out-of-order: // sequence 51, 52, 70, 53, 54, 71, 72 //switch( datagramID ) { // case 53: datagramID = 70; break; // case 71: datagramID = 53; break; // case 55: datagramID = 71; break; // default: break; //} gettimeofday( &(reportstruct->packetTime), NULL ); if ( isUDP( mSettings ) ) { // store datagram ID into buffer mBuf_UDP->id = htonl( (reportstruct->packetID)++ ); mBuf_UDP->tv_sec = htonl( reportstruct->packetTime.tv_sec ); mBuf_UDP->tv_usec = htonl( reportstruct->packetTime.tv_usec ); // delay between writes // make an adjustment for how long the last loop iteration took // TODO this doesn't work well in certain cases, like 2 parallel streams adjust = delay_target + lastPacketTime.subUsec( reportstruct->packetTime ); lastPacketTime.set( reportstruct->packetTime.tv_sec, reportstruct->packetTime.tv_usec ); if ( adjust > 0 || delay > 0 ) { delay += adjust; } } // Read the next data block from // the file if it's file input if ( isFileInput( mSettings ) ) { Extractor_getNextDataBlock( readAt, mSettings ); canRead = Extractor_canRead( mSettings ) != 0; } else canRead = true; // perform write currLen = write( mSettings->mSock, mBuf, mSettings->mBufLen ); if ( currLen < 0 && errno != ENOBUFS ) { WARN_errno( currLen < 0, "write2" ); break; } // report packets reportstruct->packetLen = currLen; ReportPacket( mSettings->reporthdr, reportstruct ); if ( delay > 0 ) { delay_loop( delay ); } if ( !mMode_Time ) { /* mAmount may be unsigned, so don't let it underflow! */ if( mSettings->mAmount >= currLen ) { mSettings->mAmount -= currLen; } else { mSettings->mAmount = 0; } } } while ( ! (sInterupted || (mMode_Time && mEndTime.before( reportstruct->packetTime )) || (!mMode_Time && 0 >= mSettings->mAmount)) && canRead ); // stop timing gettimeofday( &(reportstruct->packetTime), NULL ); CloseReport( mSettings->reporthdr, reportstruct ); if ( isUDP( mSettings ) ) { // send a final terminating datagram // Don't count in the mTotalLen. The server counts this one, // but didn't count our first datagram, so we're even now. // The negative datagram ID signifies termination to the server. // store datagram ID into buffer mBuf_UDP->id = htonl( -(reportstruct->packetID) ); mBuf_UDP->tv_sec = htonl( reportstruct->packetTime.tv_sec ); mBuf_UDP->tv_usec = htonl( reportstruct->packetTime.tv_usec ); if ( isMulticast( mSettings ) ) { write( mSettings->mSock, mBuf, mSettings->mBufLen ); } else { write_UDP_FIN( ); } } DELETE_PTR( reportstruct ); EndReport( mSettings->reporthdr ); }
/* ------------------------------------------------------------------- * Set socket options before the listen() or connect() calls. * These are optional performance tuning factors. * ------------------------------------------------------------------- */ void SetSocketOptions( thread_Settings *inSettings ) { // set the TCP window size (socket buffer sizes) // also the UDP buffer size // must occur before call to accept() for large window sizes setsock_tcp_windowsize( inSettings->mSock, inSettings->mTCPWin, (inSettings->mThreadMode == kMode_Client ? 1 : 0) ); if ( isCongestionControl( inSettings ) ) { #ifdef TCP_CONGESTION Socklen_t len = strlen( inSettings->mCongestion ) + 1; int rc = setsockopt( inSettings->mSock, IPPROTO_TCP, TCP_CONGESTION, inSettings->mCongestion, len); FAIL( rc == SOCKET_ERROR, ( "Attempt to set '%s' congestion control failed: %s\r\n", inSettings->mCongestion, strerror(errno) ), NULL ); #else fprintf( stderr, "The -Z option is not available on this operating system\r\n"); #endif /* TCP_CONGESTION */ } // check if we're sending multicast, and set TTL if ( isMulticast( inSettings ) && ( inSettings->mTTL > 0 ) ) { #ifdef HAVE_MULTICAST int val = inSettings->mTTL; if ( !SockAddr_isIPv6( &inSettings->local ) ) { int rc = setsockopt( inSettings->mSock, IPPROTO_IP, IP_MULTICAST_TTL, (const char*) &val, (Socklen_t) sizeof(val)); WARN_errno( rc == SOCKET_ERROR, ( "Failed to set multicast TTL.\r\n" ) ); } #ifdef HAVE_IPV6_MULTICAST else { int rc = setsockopt( inSettings->mSock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (const char*) &val, (Socklen_t) sizeof(val)); WARN_errno( rc == SOCKET_ERROR, ( "Failed to set multicast TTL.\r\n" ) ); } #endif /* HAVE_IPV6_MULTICAST */ #endif /* HAVE_MULTICAST */ } #ifdef IP_TOS // set IP TOS (type-of-service) field // if ( inSettings->mTOS > 0 ) { int tos, rc; tos = inSettings->mTOS; Socklen_t len = sizeof(tos); rc = setsockopt( inSettings->mSock, IPPROTO_IP, IP_TOS,(char*) &tos, len ); WARN_errno( rc == SOCKET_ERROR, ( "Failed to set IP_TOS.\r\n" ) ); // } #endif /* IP_TOS */ if ( !isUDP( inSettings ) ) { // set the TCP maximum segment size setsock_tcp_mss( inSettings->mSock, inSettings->mMSS ); #ifdef TCP_NODELAY // set TCP nodelay option if ( isNoDelay( inSettings ) ) { int nodelay = 1; Socklen_t len = sizeof(nodelay); int rc = setsockopt( inSettings->mSock, IPPROTO_TCP, TCP_NODELAY, (char*) &nodelay, len ); WARN_errno( rc == SOCKET_ERROR, ( "Failed to set TCP_NODELAY.\r\n" ) ); } #endif /* TCP_NODELAY */ } } // end SetSocketOptions
int Multicast_send_socket (const char *hostname, const char *listenport, int family, unsigned int wmem_size, struct sockaddr_storage *addr, int *addrlen) { struct addrinfo hints, *res, *ressave; int error, sockfd; if ( !listenport || !hostname ) { fprintf(stderr, "hostname and listen port required!\n"); syslog(LOG_ERR, "hostname and listen port required!\n"); return -1; } memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = family; hints.ai_socktype = SOCK_DGRAM; error = getaddrinfo(hostname, listenport, &hints, &res); if ( error ) { fprintf(stderr, "getaddrinfo error:: [%s]\n", gai_strerror(error)); syslog(LOG_ERR, "getaddrinfo error:: [%s]\n", gai_strerror(error)); return -1; } /* Try open socket with each address getaddrinfo returned, until we get a valid listening socket. */ sockfd=-1; ressave = res; while (res) { sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if ( sockfd < 0 ) { res=res->ai_next; continue; } // we found a valid socket and are done in this loop break; } if ( sockfd < 0 ) { // nothing found - bye bye fprintf(stderr, "Could not create a socket for [%s:%s]\n", hostname, listenport); syslog(LOG_ERR, "Could not create a socket for [%s:%s]\n", hostname, listenport); freeaddrinfo(ressave); return -1; } if ( isMulticast((struct sockaddr_storage *)res->ai_addr) < 0 ) { fprintf(stderr, "Not a multicast address [%s]\n", hostname); syslog(LOG_ERR, "Not a multicast address [%s]\n", hostname); freeaddrinfo(ressave); return -1; } close(sockfd); sockfd = socket(res->ai_family, SOCK_DGRAM, 0); *addrlen = res->ai_addrlen; memcpy(addr, res->ai_addr, res->ai_addrlen); /* ((struct sockaddr_in *)addr)->sin_family=AF_INET; addr.sin_addr.s_addr=inet_addr(HELLO_GROUP); addr.sin_port=htons(HELLO_PORT); */ if (joinGroup(sockfd, 1 , 1, (struct sockaddr_storage *)res->ai_addr) <0) { close(sockfd); freeaddrinfo(ressave); return -1; } freeaddrinfo(ressave); /* message = "hello world\n"; printf("Send %lu bytes, Message: %s\n", strlen(message)+1, message); while (1) { ret = sendto(sockfd,message,strlen(message)+1,0,(struct sockaddr *) addr, *addrlen); if ( ret != strlen(message)+1 ) { perror("sendto"); exit(1); } printf("sleep\n"); sleep(1); } exit(255); */ return sockfd; } /* End of Multicast_send_socket */
int Multicast_receive_socket (const char *hostname, const char *listenport, int family, int sockbuflen ) { struct addrinfo hints, *res, *ressave; socklen_t optlen; int p, error, sockfd; if ( !listenport ) { fprintf(stderr, "listen port required!\n"); syslog(LOG_ERR, "listen port required!\n"); return -1; } memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = family; hints.ai_socktype = SOCK_DGRAM; error = getaddrinfo(hostname, listenport, &hints, &res); if ( error ) { fprintf(stderr, "getaddrinfo error:: [%s]\n", gai_strerror(error)); syslog(LOG_ERR, "getaddrinfo error:: [%s]\n", gai_strerror(error)); return -1; } /* Try open socket with each address getaddrinfo returned, until we get a valid listening socket. */ sockfd = -1; ressave = res; while (res) { sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if ( sockfd < 0 ) { res=res->ai_next; continue; } // we found a valid socket and are done in this loop break; } if ( sockfd < 0 ) { // nothing found - bye bye fprintf(stderr, "Could not create a socket for [%s:%s]\n", hostname, listenport); syslog(LOG_ERR, "Could not create a socket for [%s:%s]\n", hostname, listenport); freeaddrinfo(ressave); return -1; } if ( isMulticast((struct sockaddr_storage *)res->ai_addr) < 0 ) { fprintf(stderr, "Not a multicast address [%s]\n", hostname); syslog(LOG_ERR, "Not a multicast address [%s]\n", hostname); freeaddrinfo(ressave); return -1; } close(sockfd); sockfd = socket(res->ai_family, SOCK_DGRAM, 0); if (bind(sockfd, res->ai_addr, res->ai_addrlen) < 0) { fprintf(stderr, "bind: %s\n", strerror (errno)); syslog(LOG_ERR, "bind: %s\n", strerror (errno)); close(sockfd); freeaddrinfo(ressave); return -1; } if (joinGroup(sockfd, 1 , 1, (struct sockaddr_storage *)res->ai_addr) <0) { close(sockfd); freeaddrinfo(ressave); return -1; } if ( res->ai_family == AF_INET ) syslog(LOG_DEBUG, "Joined IPv4 multicast group: %s Port: %s", hostname, listenport); if ( res->ai_family == AF_INET6 ) syslog(LOG_DEBUG, "Joined IPv6 multicat group: %s Port: %s", hostname, listenport); freeaddrinfo(ressave); if ( sockbuflen ) { if ( sockbuflen < Min_SOCKBUFF_LEN ) { sockbuflen = Min_SOCKBUFF_LEN; syslog(LOG_INFO,"I want at least %i bytes as socket buffer", sockbuflen); } optlen = sizeof(p); getsockopt(sockfd,SOL_SOCKET,SO_RCVBUF,&p,&optlen); syslog(LOG_INFO,"Standard setsockopt, SO_RCVBUF is %i Requested length is %i bytes",p, sockbuflen); if ((setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &sockbuflen, sizeof(sockbuflen)) != 0) ) { fprintf (stderr, "setsockopt(SO_RCVBUF,%d): %s\n", sockbuflen, strerror (errno)); syslog (LOG_ERR, "setsockopt(SO_RCVBUF,%d): %s", sockbuflen, strerror (errno)); close(sockfd); return -1; } else { getsockopt(sockfd,SOL_SOCKET,SO_RCVBUF,&p,&optlen); syslog(LOG_INFO,"System set setsockopt, SO_RCVBUF to %d bytes", p); } } return sockfd; } /* End of Multicast_receive_socket */
bool Nequeo::Net::Sockets::IPAddress::isUnicast() const { return !isWildcard() && !isBroadcast() && !isMulticast(); }
bool IPAddress::isUnicast() const { return !isWildcard() && !isBroadcast() && !isMulticast(); }
void rxpacket(int sock) { Packet pkt; memset(&pkt, 0, sizeof(pkt)); // using recvmsg int size; // size of the received data struct msghdr msg; memset(&msg, 0, sizeof(msg)); struct sockaddr_in from; int fromlen=sizeof(from); msg.msg_name = &from; msg.msg_namelen = fromlen; char anciliary[2048]; msg.msg_control = anciliary; msg.msg_controllen = sizeof(anciliary); struct iovec iov[1]; memset(iov, 0, sizeof(iov)); iov[0].iov_base = &pkt.data; iov[0].iov_len = sizeof(pkt.data); msg.msg_iov = iov; msg.msg_iovlen = 1; struct cmsghdr *cmsg; unsigned int ifindex; // interface index struct in_addr hdraddr; // destination IP address in IP header size = recvmsg(sock, &msg, 0); if (size == -1) { ASSERT(0); rcpLog(muxsock, RCP_PROC_RIP, RLOG_ERR, RLOG_FC_RIP, "cannot read data on socket, attempting recovery..."); exit(1); } // verify packet size int sz = size - 4; if (sz<= 0 || (sz % sizeof(RipRoute)) != 0) { rcpLog(muxsock, RCP_PROC_RIP, RLOG_DEBUG, RLOG_FC_RIP, "Invalid RIP packet size"); return; } int routes = sz / sizeof(RipRoute); int found = 0; for(cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) { if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_PKTINFO) { // struct in_pktinfo { // unsigned int ipi_ifindex; /* Interface index */ // struct in_addr ipi_spec_dst; /* Local address */ // struct in_addr ipi_addr; /* Header Destination // address */ // }; hdraddr = ((struct in_pktinfo*)CMSG_DATA(cmsg))->ipi_addr; ifindex = ((struct in_pktinfo*)CMSG_DATA(cmsg))->ipi_ifindex; found = 1; } } if (!found) return; pkt.ip_source = ntohl(from.sin_addr.s_addr); pkt.ip_dest = ntohl(hdraddr.s_addr); pkt.if_index = ifindex; // is the source ip address one of our addresses? RcpInterface *rxif = rcpFindInterface(shm, pkt.ip_source); if (rxif) { // on Linux, packets we send to the multicast group will be received back on the socket return; } char *cmd[] = {"", "request", "response"}; rcpLog(muxsock, RCP_PROC_RIP, RLOG_DEBUG, RLOG_FC_RIP, "Receiving RIP packet of size %d, from %d.%d.%d.%d, destination %d.%d.%d.%d, RIP %s, protocol version %d", size, RCP_PRINT_IP(pkt.ip_source), RCP_PRINT_IP(pkt.ip_dest), cmd[(pkt.data.command <= 2) ? pkt.data.command: 0], pkt.data.version); // update neighbor list RipNeighbor *neigh = neighbors; while (neigh != NULL) { if (neigh->ip == pkt.ip_source) { neigh->rx_time = 0; break; } neigh = neigh->next; } if (neigh == NULL) { RipNeighbor *newneigh = malloc(sizeof(RipNeighbor)); if (newneigh != NULL) { memset(newneigh, 0, sizeof(RipNeighbor)); newneigh->ip = pkt.ip_source; newneigh->next = neighbors; neighbors = newneigh; neigh = newneigh; } else { ASSERT(0); rcpLog(muxsock, RCP_PROC_RIP, RLOG_ERR, RLOG_FC_RIP, "cannot allocate memory, attempting recovery..."); exit(1); } } // do we have a valid interface? rxif =rcpFindInterfaceByKIndex(shm, pkt.if_index); if (rxif == NULL) { neigh->errors++; rcpLog(muxsock, RCP_PROC_RIP, RLOG_DEBUG, RLOG_FC_RIP, " invalid interface, dropping..."); return; } // do we have a configured neighbor? RcpRipPartner *rxnetwork = NULL; RcpRipPartner *net; int i; for (i = 0, net = shm->config.rip_neighbor; i < RCP_RIP_NEIGHBOR_LIMIT; i++, net++) { if (!net->valid) continue; // matching both source and destination addresses if (net->ip == pkt.ip_source && rxif->ip == pkt.ip_dest) { rxnetwork = net; break; } } // if no configured neighbor was found, try to find a configured network if (rxnetwork == NULL) rxnetwork = find_network_for_interface(rxif); // no network or neighbor configured, just drop the packet if (rxnetwork == NULL) { neigh->errors++; // the network can get disabled while receiving packets rcpLog(muxsock, RCP_PROC_RIP, RLOG_DEBUG, RLOG_FC_RIP, " invalid network or neighbor, dropping..."); return; } // the source of the datagram must be on a directly-connected network if ((pkt.ip_source & rxif->mask) != (rxif->ip & rxif->mask)) { neigh->errors++; // interface ip addresses are changing dynamically via CLI rcpLog(muxsock, RCP_PROC_RIP, RLOG_DEBUG, RLOG_FC_RIP, " invalid source IP address, dropping..."); return; } // drop invalid command packets if (pkt.data.command > 2) { neigh->errors++; rcpLog(muxsock, RCP_PROC_RIP, RLOG_DEBUG, RLOG_FC_RIP, " invalid RIP command, dropping..."); return; } if (pkt.data.command == 1) { rxnetwork->req_rx++; // force a response in one second rxif->rip_timeout = 1; return; } else rxnetwork->resp_rx++; ASSERT(sizeof(RipAuthMd5) == sizeof(RipAuthSimple)); ASSERT(sizeof(RipAuthSimple) == sizeof(RipRoute)); RipRoute *ptr = &pkt.data.routes[0]; int rt = 0; // if md5 auth configured, and the packet is missing the auth header, drop the packet if (rxif->rip_passwd[0] != '\0') { if (ptr->family != 0xffff || ntohs(ptr->tag) != 3) { neigh->md5_errors++; rcpLog(muxsock, RCP_PROC_RIP, RLOG_DEBUG, RLOG_FC_RIP, " missing MD5 authentication header"); return; } } // checking auth header and calculate md5 if (ptr->family == 0xffff) { // we don't care about simple auth if (ntohs(ptr->tag) == 3 && rxif->rip_passwd[0] != '\0') { RipAuthMd5 *md5 = (RipAuthMd5 *) ptr; uint16_t offset = ntohs(md5->offset); uint32_t seq = ntohl(md5->seq); rcpLog(muxsock, RCP_PROC_RIP, RLOG_DEBUG, RLOG_FC_RIP, " MD5 auth offset %u, key id %d, auth_len %d, seq %u", offset, md5->key_id, md5->auth_len, ntohl(md5->seq)); // check offset if ((offset + sizeof(RipRoute)) != size) { neigh->md5_errors++; rcpLog(muxsock, RCP_PROC_RIP, RLOG_DEBUG, RLOG_FC_RIP, " invalid offset"); return; } // check seq if (seq != 0 && seq < neigh->auth_seq) { neigh->md5_errors++; rcpLog(muxsock, RCP_PROC_RIP, RLOG_DEBUG, RLOG_FC_RIP, " invalid sequence number"); return; } neigh->auth_seq = seq; // calculate md5 uint8_t secret[16]; memset(secret, 0, 16); memcpy(secret, rxif->rip_passwd, strlen(rxif->rip_passwd)); MD5_CTX context; uint8_t digest[16]; MD5Init (&context); MD5Update (&context, (uint8_t *) &pkt, size - 16); MD5Update (&context, secret, 16); MD5Final (digest, &context); #if 0 { int i; uint8_t *p = digest; printf("rx digest:\n"); for (i = 0; i < 16; i++,p++) printf("%02x ", *p); printf("\n"); } #endif // compare md5 if (memcmp((uint8_t *) ptr + offset, digest, 16) != 0) { neigh->md5_errors++; rcpLog(muxsock, RCP_PROC_RIP, RLOG_DEBUG, RLOG_FC_RIP, " invalid MD5 digest"); return; } } ptr++; rt++; routes--; // the last route is the digest } // parsing routes while (rt < routes) { uint32_t metric = ntohl(ptr->metric); uint32_t mask = ntohl(ptr->mask); uint32_t ip = ntohl(ptr->ip); uint32_t gw = ntohl(ptr->gw); // if (trace_prefix == 0 || // (trace_prefix != 0 && trace_prefix == ip)) { // if (gw == 0) // rcpLog(muxsock, RCP_PROC_RIP, RLOG_DEBUG, RLOG_FC_RIP, // " %d.%d.%d.%d/%d metric %u", // RCP_PRINT_IP(ip), // mask2bits(mask), // metric); // else // rcpLog(muxsock, RCP_PROC_RIP, RLOG_DEBUG, RLOG_FC_RIP, // " %d.%d.%d.%d/%d metric %u next hop %d.%d.%d.%d", // RCP_PRINT_IP(ip), // mask2bits(mask), // metric, // RCP_PRINT_IP(gw)); // } // only AF_INET family is supported if (ntohs(ptr->family) != AF_INET) { neigh->route_errors++; rcpLog(muxsock, RCP_PROC_RIP, RLOG_DEBUG, RLOG_FC_RIP, " invalid route family"); goto next_element; } // check destination for loopback addresses if (isLoopback(ip)) { neigh->route_errors++; rcpLog(muxsock, RCP_PROC_RIP, RLOG_DEBUG, RLOG_FC_RIP, " invalid loopback route prefix"); goto next_element; } // check destination for broadcast addresses if (isBroadcast(ip)) { neigh->route_errors++; rcpLog(muxsock, RCP_PROC_RIP, RLOG_DEBUG, RLOG_FC_RIP, " invalid broadcast route prefix"); goto next_element; } // check destination for multicast addresses if (isMulticast(ip)) { neigh->route_errors++; rcpLog(muxsock, RCP_PROC_RIP, RLOG_DEBUG, RLOG_FC_RIP, " invalid multicast route prefix"); goto next_element; } // validate route metric else if (metric > 16 || metric == 0) { neigh->route_errors++; rcpLog(muxsock, RCP_PROC_RIP, RLOG_DEBUG, RLOG_FC_RIP, " invalid metric"); goto next_element; } // validate route entry if (ip == 0 && mask == 0) { rcpLog(muxsock, RCP_PROC_RIP, RLOG_DEBUG, RLOG_FC_RIP, " received default route metric %d", metric); } else if (pkt.data.version == 2 && mask == 0) { neigh->route_errors++; rcpLog(muxsock, RCP_PROC_RIP, RLOG_DEBUG, RLOG_FC_RIP, " invalid RIP route"); goto next_element; } else if (pkt.data.version == 1 && mask != 0) { neigh->route_errors++; rcpLog(muxsock, RCP_PROC_RIP, RLOG_DEBUG, RLOG_FC_RIP, " invalid RIP route"); goto next_element; } // check if the mask is contiguous if (mask != 0 && !maskContiguous(mask)) { neigh->route_errors++; rcpLog(muxsock, RCP_PROC_RIP, RLOG_DEBUG, RLOG_FC_RIP, " invalid mask"); goto next_element; } // validate next hop if (gw) { if (isLoopback(gw) || isMulticast(gw) || isBroadcast(gw)) { neigh->route_errors++; rcpLog(muxsock, RCP_PROC_RIP, RLOG_DEBUG, RLOG_FC_RIP, " invalid next hop"); goto next_element; } } // manufacture mask for rip v1 if (pkt.data.version == 1) mask = classMask(ip); // RFC metric = metric + interface cost // we assume a cost of 1 for each interface metric++; // add the route in the database if (metric < 16) { //RFC //- Setting the destination address to the destination address in the // RTE // // - Setting the metric to the newly calculated metric (as described // above) // // - Set the next hop address to be the address of the router from which // the datagram came // // - Initialize the timeout for the route. If the garbage-collection // timer is running for this route, stop it (see section 3.6 for a // discussion of the timers) // // - Set the route change flag // // - Signal the output process to trigger an update (see section 3.8.1) // a next hop of 0 means send the packets to me if (gw == 0) gw = pkt.ip_source; ripdb_add(RCP_ROUTE_RIP, ip, mask, gw, metric, pkt.ip_source, rxif); } else { // a next hop of 0 means send the packets to me if (gw == 0) gw = pkt.ip_source; ripdb_delete(RCP_ROUTE_RIP, ip, mask, gw, pkt.ip_source); } next_element: ptr++; rt++; } }
bool IPEndpoint::V4::isPublic () const { return !isPrivate() && !isBroadcast() && !isMulticast(); }