Exemplo n.º 1
0
/* -------------------------------------------------------------------
 * 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
Exemplo n.º 2
0
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;
}
Exemplo n.º 3
0
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 );
} 
Exemplo n.º 4
0
/* -------------------------------------------------------------------
 * 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
Exemplo n.º 5
0
Arquivo: nfnet.c Projeto: Tilka/nfdump
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 */
Exemplo n.º 6
0
Arquivo: nfnet.c Projeto: Tilka/nfdump
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 */
Exemplo n.º 7
0
bool Nequeo::Net::Sockets::IPAddress::isUnicast() const
{
	return !isWildcard() && !isBroadcast() && !isMulticast();
}
Exemplo n.º 8
0
bool IPAddress::isUnicast() const
{
	return !isWildcard() && !isBroadcast() && !isMulticast();
}
Exemplo n.º 9
0
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++;
	}
}
Exemplo n.º 10
0
bool IPEndpoint::V4::isPublic () const
{
    return !isPrivate() && !isBroadcast() && !isMulticast();
}