Beispiel #1
0
vector get_routes_by_table(int table,int family){

	vector routes;
	vector_init(&routes);

	struct{
		struct nlmsghdr n;
		struct rtmsg r;
		char buf[1024];
	}route_req;

	memset(&route_req, 0, sizeof(route_req));

	struct rtnl_handle rth;
    	if (rtnl_open(&rth, 0) < 0){
		printf("cannot open rtnetlink\n");
		return routes;
	}

	route_req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
	route_req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
	route_req.n.nlmsg_type = RTM_GETROUTE;

	route_req.r.rtm_family = family;
	route_req.r.rtm_table = table;
	route_req.r.rtm_dst_len = 0;
	route_req.r.rtm_src_len = 0;

	int nbytes=0,reply_len=0;//ret, count=0;
	ssize_t counter = 5000;
	char reply_ptr[5000];
	char* buf = reply_ptr;
	struct nlmsghdr *nlp;
	struct rtmsg *rtp;
	struct rtattr *rtap;
	int rtl;
	unsigned long bufsize ;

	nlp = malloc(sizeof(struct nlmsghdr));
	memset(nlp, 0, sizeof(struct nlmsghdr));
	
	int rbytes __attribute__((unused)) = rtnl_dump_request(&rth,RTM_GETROUTE,&route_req,sizeof(route_req));

	for(;;){
		if( counter < sizeof(struct nlmsghdr)){
			printf("Routing table is bigger than %lu\n", sizeof(reply_ptr));
			vector_free(&routes);
			return routes;
		}

		nbytes = recv(rth.fd, &reply_ptr[reply_len], counter, 0);

		if(nbytes < 0 ){
			printf("Error in recv\n");
			break;
		}
		
		if(nbytes == 0)
			printf("EOF in netlink\n");
	
		nlp = (struct nlmsghdr*)(&reply_ptr[reply_len]);
	
		if (nlp->nlmsg_type == NLMSG_DONE){
			// All data has been received.
			// Truncate the reply to exclude this message,
			// i.e. do not increase reply_len.
			break;
		}

		if (nlp->nlmsg_type == NLMSG_ERROR){
			printf("Error in msg\n");
			vector_free(&routes);
			return routes;
	}

		reply_len += nbytes;
		counter -= nbytes;
	}

	bufsize = reply_len;
	nlp = (struct nlmsghdr*)buf;
	
    	for (;NLMSG_OK(nlp, bufsize); nlp = NLMSG_NEXT(nlp, bufsize)){
		
		/* Get the route data */
        	rtp = (struct rtmsg *) NLMSG_DATA(nlp);

		/* We only need route from the specific protocol*/
		if (rtp->rtm_table != table)
			continue;
	
        	/* Get attributes of route_entry */
        	rtap = (struct rtattr *) RTM_RTA(rtp);

        	/* Get the route atttibutes len */
        	rtl = RTM_PAYLOAD(nlp);
        	/* Loop through all attributes */

		struct netlink_route *route = malloc(sizeof(struct netlink_route));
		route->proto = rtp->rtm_protocol;
		route->prefix = rtp->rtm_dst_len;

        	for ( ; RTA_OK(rtap, rtl);rtap = RTA_NEXT(rtap, rtl)){
			
			if(rtap->rta_type == RTA_DST){
				struct sockaddr_storage dest;
				if(family == AF_INET){
					((struct sockaddr_in*)&dest)->sin_addr.s_addr = (unsigned long) RTA_DATA(rtap);
					dest.ss_family = AF_INET;
				}else{
					memcpy(&((struct sockaddr_in6*)&dest)->sin6_addr.s6_addr,RTA_DATA(rtap),16);
					dest.ss_family = AF_INET6;
				}
				route->dest = dest;
			}
			if(rtap->rta_type == RTA_GATEWAY){
				struct sockaddr_storage dest;
				if(family == AF_INET){
					((struct sockaddr_in*)&dest)->sin_addr.s_addr = (unsigned long) RTA_DATA(rtap);
					dest.ss_family = AF_INET;
				}else{
					memcpy(&((struct sockaddr_in6*)&dest)->sin6_addr.s6_addr,RTA_DATA(rtap),16);
					dest.ss_family = AF_INET6;
				}
				route->gateway = dest;
			}
			if(rtap->rta_type == RTA_PRIORITY){
				route->metric = *(unsigned long *) RTA_DATA(rtap);
			}

        	}

		vector_add(&routes,route);

    	}

	rtnl_close(&rth);

	return routes;
}
Beispiel #2
0
/*
 * See if left->addr or left->next is %defaultroute and change it to IP.
 *
 * Returns:
 * -1: failure
 *  0: done
 *  1: please call again: more to do
 */
static int resolve_defaultroute_one(struct starter_end *host,
				struct starter_end *peer)
{
	/*
	 * "left="         == host->addrtype and host->addr
	 * "leftnexthop="  == host->nexttype and host->nexthop
	 */

	/* What kind of result are we seeking? */
	bool seeking_src = (host->addrtype == KH_DEFAULTROUTE);
	bool seeking_gateway = (host->nexttype == KH_DEFAULTROUTE);

	char msgbuf[RTNL_BUFSIZE];
	bool has_dst = FALSE;
	int query_again = 0;

	if (!seeking_src && !seeking_gateway)
		return 0;	/* this end already figured out */

	/* Fill netlink request */
	netlink_query_init(msgbuf, host->addr_family);
	if (host->nexttype == KH_IPADDR) {
		/*
		 * My nexthop (gateway) is specified.
		 * We need to figure out our source IP to get there.
		 */
		netlink_query_add(msgbuf, RTA_DST, &host->nexthop);
		has_dst = TRUE;
	} else if (peer->addrtype == KH_IPADDR) {
		/*
		 * Peer IP is specified.
		 * We may need to figure out source IP
		 * and gateway IP to get there.
		 */
		netlink_query_add(msgbuf, RTA_DST, &peer->addr);
		has_dst = TRUE;
		if (seeking_src && seeking_gateway &&
			host->addr_family == AF_INET) {
			/*
			 * If we have only peer IP and no gateway/src we must
			 * do two queries:
			 * 1) find out gateway for dst
			 * 2) find out src for that gateway
			 * Doing both in one query returns src for dst.
			 *
			 * (IPv6 returns link-local for gateway so we can and
			 * do seek both in one query.)
			 */
			seeking_src = FALSE;
			query_again = 1;
		}
	}
	if (has_dst && host->addrtype == KH_IPADDR) {
		/* SRC works only with DST */
		netlink_query_add(msgbuf, RTA_SRC, &host->addr);
	}

	/*
	 * If we have for example host=%defaultroute + peer=%any
	 * (no destination) the netlink reply will be full routing table.
	 * We must do two queries:
	 * 1) find out default gateway
	 * 2) find out src for that default gateway
	 */
	if (!has_dst && seeking_src && seeking_gateway) {
		seeking_src = FALSE;
		query_again = 1;
	}
	if (seeking_gateway) {
		struct nlmsghdr *nlmsg = (struct nlmsghdr *)msgbuf;

		nlmsg->nlmsg_flags |= NLM_F_DUMP;
	}

	if (verbose)
		printf("\nseeking_src = %d, seeking_gateway = %d, has_dst = %d\n",
			seeking_src, seeking_gateway, has_dst);

	/* Send netlink get_route request */

	ssize_t len = netlink_query(msgbuf);

	if (len < 0)
		return -1;

	/* Parse reply */
	struct nlmsghdr *nlmsg = (struct nlmsghdr *)msgbuf;

	/*
	 * The cast to unsigned short is to dodge an error in
	 * netlink.h:NLMSG_OK() which triggers a GCC warning in recent
	 * versions of GCC (2014 August):
	 * error: comparison between signed and unsigned integer expressions
	 * Note: as long as RTNL_BUFSIZE <= USHRT_MAX, this is safe.
	 */
	for (; NLMSG_OK(nlmsg, (unsigned short)len); nlmsg = NLMSG_NEXT(nlmsg, len)) {
		char r_interface[IF_NAMESIZE+1];
		char r_source[ADDRTOT_BUF];
		char r_gateway[ADDRTOT_BUF];
		char r_destination[ADDRTOT_BUF];

		if (nlmsg->nlmsg_type == NLMSG_DONE)
			break;

		if (nlmsg->nlmsg_type == NLMSG_ERROR) {
			printf("netlink error\n");
			return -1;
		}

		/* ignore all but IPv4 and IPv6 */
		struct rtmsg *rtmsg = (struct rtmsg *) NLMSG_DATA(nlmsg);

		if (rtmsg->rtm_family != AF_INET &&
			rtmsg->rtm_family != AF_INET6)
			continue;

		/* Parse one route entry */
		zero(&r_interface);
		r_source[0] = r_gateway[0] = r_destination[0] = '\0';

		struct rtattr *rtattr = (struct rtattr *) RTM_RTA(rtmsg);
		int rtlen = RTM_PAYLOAD(nlmsg);

		while (RTA_OK(rtattr, rtlen)) {
			switch (rtattr->rta_type) {
			case RTA_OIF:
				if_indextoname(*(int *)RTA_DATA(rtattr),
					r_interface);
				break;

			case RTA_PREFSRC:
				inet_ntop(rtmsg->rtm_family, RTA_DATA(rtattr),
					r_source, sizeof(r_source));
				break;

			case RTA_GATEWAY:
				inet_ntop(rtmsg->rtm_family, RTA_DATA(rtattr),
					r_gateway, sizeof(r_gateway));
				break;

			case RTA_DST:
				inet_ntop(rtmsg->rtm_family, RTA_DATA(rtattr),
					r_destination,
					sizeof(r_destination));
				break;
			}
			rtattr = RTA_NEXT(rtattr, rtlen);
		}

		/*
		 * Ignore if not main table.
		 * Ignore ipsecX or mastX interfaces.
		 */
		bool ignore = rtmsg->rtm_table != RT_TABLE_MAIN ||
			startswith(r_interface, "ipsec") ||
			startswith(r_interface, "mast");

		if (verbose) {
			printf("dst %s via %s dev %s src %s table %d%s\n",
				r_destination,
				r_gateway,
				r_interface,
				r_source, rtmsg->rtm_table,
				ignore ? "" : " (ignored)");
		}

		if (ignore)
			continue;

		if (seeking_src && r_source[0] != '\0') {
			err_t err = tnatoaddr(r_source, 0, rtmsg->rtm_family,
					&host->addr);

			if (err == NULL) {
				host->addrtype = KH_IPADDR;
				seeking_src = FALSE;
				if (verbose)
					printf("set addr: %s\n", r_source);
			} else if (verbose) {
				printf("unknown source results from kernel (%s): %s\n",
					r_source, err);
			}
		}

		if (seeking_gateway && r_destination[0] == '\0' &&
			(has_dst || r_source[0] == '\0')) {
			if (r_gateway[0] == '\0' && r_interface[0] != '\0') {
				/*
				 * Point-to-Point default gw without "via IP"
				 * Attempt to find r_gateway as the IP address
				 * on the interface.
				 */
				resolve_ppp_peer(r_interface, host->addr_family,
						 r_gateway);
			}
			if (r_gateway[0] != '\0') {
				err_t err = tnatoaddr(r_gateway, 0,
						rtmsg->rtm_family,
						&host->nexthop);

				if (err != NULL) {
					printf("unknown gateway results from kernel: %s\n",
						err);
				} else {
					/* Note: Use first even if multiple */
					host->nexttype = KH_IPADDR;
					seeking_gateway = FALSE;
					if (verbose)
						printf("set nexthop: %s\n",
							r_gateway);
				}
			}
		}
	}
	return query_again;
}
/*
 * Parse a RTM_NEWROUTE or RTM_DELROUTE message.
 */
bool NetlinkEvent::parseRtMessage(const struct nlmsghdr *nh) {
    uint8_t type = nh->nlmsg_type;
    const char *msgname = rtMessageName(type);

    // Sanity check.
    if (type != RTM_NEWROUTE && type != RTM_DELROUTE) {
        SLOGE("%s: incorrect message type %d (%s)\n", __func__, type, msgname);
        return false;
    }

    struct rtmsg *rtm = (struct rtmsg *) NLMSG_DATA(nh);
    if (!checkRtNetlinkLength(nh, sizeof(*rtm)))
        return false;

    if (// Ignore static routes we've set up ourselves.
        (rtm->rtm_protocol != RTPROT_KERNEL &&
         rtm->rtm_protocol != RTPROT_RA) ||
        // We're only interested in global unicast routes.
        (rtm->rtm_scope != RT_SCOPE_UNIVERSE) ||
        (rtm->rtm_type != RTN_UNICAST) ||
        // We don't support source routing.
        (rtm->rtm_src_len != 0) ||
        // Cloned routes aren't real routes.
        (rtm->rtm_flags & RTM_F_CLONED)) {
        return false;
    }

    int family = rtm->rtm_family;
    int prefixLength = rtm->rtm_dst_len;

    // Currently we only support: destination, (one) next hop, ifindex.
    char dst[INET6_ADDRSTRLEN] = "";
    char gw[INET6_ADDRSTRLEN] = "";
    char dev[IFNAMSIZ] = "";

    size_t len = RTM_PAYLOAD(nh);
    struct rtattr *rta;
    for (rta = RTM_RTA(rtm); RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) {
        switch (rta->rta_type) {
            case RTA_DST:
                if (maybeLogDuplicateAttribute(*dst, "RTA_DST", msgname))
                    continue;
                if (!inet_ntop(family, RTA_DATA(rta), dst, sizeof(dst)))
                    return false;
                continue;
            case RTA_GATEWAY:
                if (maybeLogDuplicateAttribute(*gw, "RTA_GATEWAY", msgname))
                    continue;
                if (!inet_ntop(family, RTA_DATA(rta), gw, sizeof(gw)))
                    return false;
                continue;
            case RTA_OIF:
                if (maybeLogDuplicateAttribute(*dev, "RTA_OIF", msgname))
                    continue;
                if (!if_indextoname(* (int *) RTA_DATA(rta), dev))
                    return false;
            default:
                continue;
        }
    }

   // If there's no RTA_DST attribute, then:
   // - If the prefix length is zero, it's the default route.
   // - If the prefix length is nonzero, there's something we don't understand.
   //   Ignore the event.
   if (!*dst && !prefixLength) {
        if (family == AF_INET) {
            strncpy(dst, "0.0.0.0", sizeof(dst));
        } else if (family == AF_INET6) {
            strncpy(dst, "::", sizeof(dst));
        }
    }

    // A useful route must have a destination and at least either a gateway or
    // an interface.
    if (!*dst || (!*gw && !*dev))
        return false;

    // Fill in netlink event information.
    mAction = (type == RTM_NEWROUTE) ? NlActionRouteUpdated :
                                       NlActionRouteRemoved;
    mSubsystem = strdup("net");
    asprintf(&mParams[0], "ROUTE=%s/%d", dst, prefixLength);
    asprintf(&mParams[1], "GATEWAY=%s", (*gw) ? gw : "");
    asprintf(&mParams[2], "INTERFACE=%s", (*dev) ? dev : "");

    return true;
}
Beispiel #4
0
int getSenderInterface(unsigned int targetIP, char* device, char* mac)
{
    struct nlmsghdr* nlMsg;

    char               msgBuf[BUFSIZE];

    int sock;
    ssize_t len = 0;
    uint32_t msgSeq = 0;

    if ((sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE)) < 0)
    {
        syslog(LOG_ERR, "unable to create socket: '%s'", strerror(errno));
        return -1;
    }

    memset(msgBuf, 0, BUFSIZE);

    nlMsg = (struct nlmsghdr *)msgBuf;
    nlMsg->nlmsg_len   = NLMSG_LENGTH(sizeof(struct rtmsg));
    nlMsg->nlmsg_type  = RTM_GETROUTE;
    nlMsg->nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST;
    nlMsg->nlmsg_seq   = msgSeq++;
    nlMsg->nlmsg_pid   = getpid();

    if (send(sock, nlMsg, nlMsg->nlmsg_len, 0) < 0)
    {
        syslog(LOG_ERR, "unable to write to socket: '%s'", strerror(errno));
        close(sock);
        return -1;
    }

    if ((len = readNlSock(sock, msgBuf, msgSeq, getpid())) < 0)
    {
        syslog(LOG_ERR, "unable to read from socket: '%s'", strerror(errno));
        close(sock);
        return -1;
    }

    for (; nlmsg_ok(nlMsg, len); nlMsg = NLMSG_NEXT(nlMsg, len)) {
        struct rtmsg*  rtMsg = (struct rtmsg *)NLMSG_DATA(nlMsg);

        if (rtMsg->rtm_family == AF_INET || rtMsg->rtm_table == RT_TABLE_MAIN)
        {
            struct rtattr* rtAttr = (struct rtattr *)RTM_RTA(rtMsg);
            int            rtLen  = RTM_PAYLOAD(nlMsg);
            char           ifName[IF_NAMESIZE] = {0};
            unsigned int   dstAddr = 0, dstMask = 1;
            for (; RTA_OK(rtAttr, rtLen); rtAttr = RTA_NEXT(rtAttr, rtLen)) {
                switch (rtAttr->rta_type)
                {
                    case RTA_OIF:
                        if_indextoname(*(int *)RTA_DATA(rtAttr), ifName);
                        break;
                    case RTA_DST:
                        dstAddr = *(u_int *)RTA_DATA(rtAttr);
                        dstMask = rtLen;
                        break;
                }
            }
            if (dstMask <= 32)
            {
                dstMask = htonl(ntohl(inet_addr("255.255.255.255")) << (32 - dstMask));
                if ((dstAddr & dstMask) == (targetIP & dstMask))
                {
                    if (getInterfaceMac(ifName, mac) == 0)
                    {
                        close(sock);
                        snprintf(device, IFNAMSIZ, "%s", ifName);
                        syslog(LOG_INFO, "sending from device '%s' with MAC address '%s'",
                                device,
                                printMACStr(mac));
                        return 0;
                    }
                }
            }
        }
    }
    close(sock);
    return 1;
}
Beispiel #5
0
static void netlink_route(struct ufpd_thread *thread, struct nlmsghdr *nlh)
{
	struct rtmsg *route_entry;
	struct rtattr *route_attr;
	struct fib *fib;
	int route_attr_len, family;
	uint8_t prefix[16] = {};
	uint8_t nexthop[16] = {};
	unsigned int prefix_len;
	int ifindex, port_index, i;
	enum fib_type type;

	route_entry = (struct rtmsg *)NLMSG_DATA(nlh);
	family		= route_entry->rtm_family;
	prefix_len	= route_entry->rtm_dst_len;
	ifindex		= -1;
	port_index	= -1;
	type		= FIB_TYPE_LINK;

	route_attr = (struct rtattr *)RTM_RTA(route_entry);
	route_attr_len = RTM_PAYLOAD(nlh);

	while(RTA_OK(route_attr, route_attr_len)){
		switch(route_attr->rta_type){
		case RTA_DST:
			memcpy(prefix, RTA_DATA(route_attr),
				RTA_PAYLOAD(route_attr));
			break;
		case RTA_GATEWAY:
			memcpy(nexthop, RTA_DATA(route_attr),
				RTA_PAYLOAD(route_attr));
			type = FIB_TYPE_FORWARD;
			break;
		case RTA_OIF:
			ifindex = *(int *)RTA_DATA(route_attr);
			break;
		default:
			break;
		}

		route_attr = RTA_NEXT(route_attr, route_attr_len);
	}

	if(route_entry->rtm_table == RT_TABLE_LOCAL)
		type = FIB_TYPE_LOCAL;

	for(i = 0; i < thread->num_ports; i++){
		if(ufp_tun_index(thread->plane, i) == ifindex){
			port_index = i;
			break;
		}
	}

	switch(family){
	case AF_INET:
		fib = thread->fib_inet;
		break;
	case AF_INET6:
		fib = thread->fib_inet6;
		break;
	default:
		goto out;
		break;
	}

	switch(nlh->nlmsg_type){
	case RTM_NEWROUTE:
		fib_route_update(fib, family, type,
			prefix, prefix_len, nexthop, port_index, ifindex,
			thread->mpool);
		break;
	case RTM_DELROUTE:
		fib_route_delete(fib, family,
			prefix, prefix_len, ifindex);
		break;
	default:
		break;
	}

out:
	return;
}
Beispiel #6
0
Datei: nl.c Projekt: saga/mono
int
ReadEvents (gpointer sock, gpointer buffer, gint32 count, gint32 size)
{
	struct nlmsghdr *nlp;
	struct rtmsg *rtp;
	int rtl;
	struct rtattr *rtap;
	int result;
	int s;

	NL_DEBUG_PRINT ("ENTER ReadEvents()");
	result = EVT_NONE;
	s = GPOINTER_TO_INT (sock);
	/* This socket is not found by IO layer, so we do everything here */
	if (count == 0) {
		while ((count = recv (s, buffer, size, 0)) == -1 && errno == EINTR);
		if (count <= 0) {
			NL_DEBUG_PRINT ("EXIT ReadEvents()");
			return result;
		}
	}
	for (nlp = (struct nlmsghdr *) buffer; NLMSG_OK (nlp, count); nlp = NLMSG_NEXT (nlp, count)) {
		int family;
		int addr_length;
		int msg_type;
		int table;
		int protocol;
		int scope;
		int rtm_type;
		gboolean have_dst;
		gboolean have_src;
		gboolean have_pref_src;
		gboolean have_gw;
#ifdef AF_INET6
		char dst [16];
		char src [16];
		char pref_src [16];
		char gw [16];
#else
		char dst [4];
		char src [4];
		char pref_src [4];
		char gw [4];
#endif

		msg_type = nlp->nlmsg_type;
		NL_DEBUG_PRINT ("TYPE: %d %s", msg_type, FIND_RT_TYPE_NAME (msg_type));
		if (msg_type != RTM_NEWROUTE && msg_type != RTM_DELROUTE)
			continue;

		rtp = (struct rtmsg *) NLMSG_DATA (nlp);
		family = rtp->rtm_family;
#ifdef AF_INET6
		addr_length = (family == AF_INET) ? 4 : 16;
#else
		addr_length = 4;
#endif
		table = rtp->rtm_table;
		protocol = rtp->rtm_protocol;
		scope = rtp->rtm_scope;
		rtm_type = rtp->rtm_type;
		NL_DEBUG_PRINT ("\tRTMSG table: %d %s", table, FIND_RT_TABLE_NAME (table));
		if (table != RT_TABLE_MAIN && table != RT_TABLE_LOCAL)
			continue;

		NL_DEBUG_PRINT ("\tRTMSG protocol: %d %s", protocol, FIND_RTM_PROTO_NAME (protocol));
		NL_DEBUG_PRINT ("\tRTMSG scope: %d %s", scope, FIND_RTM_SCOPE_NAME (scope));
		NL_DEBUG_PRINT ("\tRTMSG type: %d %s", rtm_type, FIND_RTM_TYPE_NAME (rtm_type));

		rtap = (struct rtattr *) RTM_RTA (rtp);
		rtl = RTM_PAYLOAD (nlp);
		// loop & get every attribute
		//
		// 
		// NEW_ROUTE
		// 	table = RT_TABLE_LOCAL, Scope = HOST + pref.src == src  + type=LOCAL -> new if addr
		// 	RT_TABLE_MAIN, Scope = Universe, unicast, gateway exists -> NEW default route
		// DEL_ROUTE
		// 	table = RT_TABLE_LOCAL, Scope = HOST, perfsrc = dst  + type=LOCAL -> if addr deleted
		// 	RT_TABLE_MAIN - DELROUTE + unicast -> event (gw down?)
		have_dst = have_src = have_pref_src = have_gw = FALSE;
		for(; RTA_OK (rtap, rtl); rtap = RTA_NEXT(rtap, rtl)) {
			char *data;
#ifdef NL_DEBUG
#ifdef AF_INET6
			char ip [INET6_ADDRSTRLEN];
			int ip_length = INET6_ADDRSTRLEN;
#else
			char ip [INET_ADDRSTRLEN];
			int ip_length = INET_ADDRSTRLEN;
#endif
#endif

			NL_DEBUG_PRINT ("\tAttribute: %d %d (%s)", rtap->rta_len, rtap->rta_type, FIND_RTM_ATTRS_NAME (rtap->rta_type));
			data = RTA_DATA (rtap);
			switch (rtap->rta_type) {
			case RTA_DST:
				have_dst = TRUE;
				memcpy (dst, data, addr_length);
#ifdef NL_DEBUG
				*ip = 0;
				inet_ntop (family, RTA_DATA (rtap), ip, ip_length);
				NL_DEBUG_PRINT ("\t\tDst: %s", ip);
#endif
				break;
			case RTA_PREFSRC:
				have_pref_src = TRUE;
				memcpy (pref_src, data, addr_length);
#ifdef NL_DEBUG
				*ip = 0;
				inet_ntop (family, RTA_DATA (rtap), ip, ip_length);
				NL_DEBUG_PRINT ("\t\tPref. Src.: %s", ip);
#endif
				break;
			case RTA_SRC:
				have_src = TRUE;
				memcpy (src, data, addr_length);
#ifdef NL_DEBUG
				*ip = 0;
				inet_ntop (family, RTA_DATA (rtap), ip, ip_length);
				NL_DEBUG_PRINT ("\tSrc: %s", ip);
#endif
				break;
			case RTA_GATEWAY:
				have_gw = TRUE;
				memcpy (gw, data, addr_length);
#ifdef NL_DEBUG
				*ip = 0;
				inet_ntop (family, RTA_DATA (rtap), ip, ip_length);
				NL_DEBUG_PRINT ("\t\tGateway: %s", ip);
#endif
				break;
			default:
				break;
			}
		}
		if (msg_type == RTM_NEWROUTE) {
			if (table == RT_TABLE_MAIN) {
				NL_DEBUG_PRINT ("NEWROUTE: Availability changed");
				result |= EVT_AVAILABILITY;
			} else if (table == RT_TABLE_LOCAL) {
				NL_DEBUG_PRINT ("NEWROUTE: new IP");
				if (have_dst && have_pref_src && memcmp (dst, pref_src, addr_length) == 0)
					result |= EVT_ADDRESS;
			}
		} else if (msg_type == RTM_DELROUTE) {
			if (table == RT_TABLE_MAIN) {
				if (rtm_type == RTN_UNICAST && (have_dst || have_pref_src)) {
					result |= EVT_AVAILABILITY;
					NL_DEBUG_PRINT ("DELROUTE: Availability changed");
				}
			} else if (table == RT_TABLE_LOCAL) {
				if (have_dst && have_pref_src && memcmp (dst, pref_src, addr_length) == 0) {
					result |= EVT_ADDRESS;
					NL_DEBUG_PRINT ("DELROUTE: deleted IP");
				}
			}
		}
		while ((count = recv (s, buffer, size, 0)) == -1 && errno == EINTR);
		if (count <= 0) {
			NL_DEBUG_PRINT ("EXIT ReadEvents() -> %d", result);
			return result;
		}
		nlp = (struct nlmsghdr *) buffer;
	}
	NL_DEBUG_PRINT ("EXIT ReadEvents() -> %d", result);
	return result;
}
Beispiel #7
0
static int
if_copyrt(struct dhcpcd_ctx *ctx, struct rt *rt, struct nlmsghdr *nlm)
{
	size_t len;
	struct rtmsg *rtm;
	struct rtattr *rta;
	unsigned int ifindex;
	struct sockaddr *sa;

	len = nlm->nlmsg_len - sizeof(*nlm);
	if (len < sizeof(*rtm)) {
		errno = EBADMSG;
		return -1;
	}
	rtm = (struct rtmsg *)NLMSG_DATA(nlm);
	if (rtm->rtm_table != RT_TABLE_MAIN)
		return -1;

	memset(rt, 0, sizeof(*rt));
	if (rtm->rtm_type == RTN_UNREACHABLE)
		rt->rt_flags |= RTF_REJECT;

	rta = (struct rtattr *)RTM_RTA(rtm);
	len = RTM_PAYLOAD(nlm);
	while (RTA_OK(rta, len)) {
		sa = NULL;
		switch (rta->rta_type) {
		case RTA_DST:
			sa = &rt->rt_dest;
			break;
		case RTA_GATEWAY:
			sa = &rt->rt_gateway;
			break;
		case RTA_PREFSRC:
			sa = &rt->rt_ifa;
			break;
		case RTA_OIF:
			ifindex = *(unsigned int *)RTA_DATA(rta);
			rt->rt_ifp = if_findindex(ctx->ifaces, ifindex);
			break;
		case RTA_PRIORITY:
			rt->rt_metric = *(unsigned int *)RTA_DATA(rta);
			break;
		case RTA_METRICS:
		{
			struct rtattr *r2;
			size_t l2;

			l2 = rta->rta_len;
			r2 = (struct rtattr *)RTA_DATA(rta);
			while (RTA_OK(r2, l2)) {
				switch (r2->rta_type) {
				case RTAX_MTU:
					rt->rt_mtu = *(unsigned int *)RTA_DATA(r2);
					break;
				}
				r2 = RTA_NEXT(r2, l2);
			}
			break;
		}
		}

		if (sa != NULL) {
			socklen_t salen;

			sa->sa_family = rtm->rtm_family;
			salen = sa_addrlen(sa);
			memcpy((char *)sa + sa_addroffset(sa), RTA_DATA(rta),
			    MIN(salen, RTA_PAYLOAD(rta)));
		}

		rta = RTA_NEXT(rta, len);
	}

	/* If no RTA_DST set the unspecified address for the family. */
	if (rt->rt_dest.sa_family == AF_UNSPEC)
		rt->rt_dest.sa_family = rtm->rtm_family;

	rt->rt_netmask.sa_family = rtm->rtm_family;
	sa_fromprefix(&rt->rt_netmask, rtm->rtm_dst_len);
	if (sa_is_allones(&rt->rt_netmask))
		rt->rt_flags |= RTF_HOST;

	#if 0
	if (rt->rtp_ifp == NULL && rt->src.s_addr != INADDR_ANY) {
		struct ipv4_addr *ap;

		/* For some reason the default route comes back with the
		 * loopback interface in RTA_OIF? Lets find it by
		 * preferred source address */
		if ((ap = ipv4_findaddr(ctx, &rt->src)))
			rt->iface = ap->iface;
	}
	#endif

	if (rt->rt_ifp == NULL) {
		errno = ESRCH;
		return -1;
	}
	return 0;
}
Beispiel #8
0
static void rtnl_print_route(struct nlmsghdr *hdr)
{
	struct rtmsg *rtm = NLMSG_DATA(hdr);
	uint32_t attrs_len = RTM_PAYLOAD(hdr);
	struct rtattr *attr = RTM_RTA(rtm);
	struct rta_cacheinfo *ci;
	int hz = get_user_hz();
	char addr_str[256];
	char flags[256];

	tprintf(" [ Route Family %d (%s%s%s)", rtm->rtm_family,
			colorize_start(bold),
			addr_family2str(rtm->rtm_family),
			colorize_end());
	tprintf(", Dst Len %d", rtm->rtm_dst_len);
	tprintf(", Src Len %d", rtm->rtm_src_len);
	tprintf(", ToS %d", rtm->rtm_tos);
	tprintf(", Table %d (%s%s%s)", rtm->rtm_table,
			colorize_start(bold),
			route_table2str(rtm->rtm_table),
			colorize_end());
	tprintf(", Proto %d (%s%s%s)", rtm->rtm_protocol,
			colorize_start(bold),
			route_proto2str(rtm->rtm_protocol),
			colorize_end());
	tprintf(", Scope %d (%s%s%s)", rtm->rtm_scope,
			colorize_start(bold),
			scope2str(rtm->rtm_scope),
			colorize_end());
	tprintf(", Type %d (%s%s%s)", rtm->rtm_type,
			colorize_start(bold),
			route_type2str(rtm->rtm_type),
			colorize_end());
	tprintf(", Flags 0x%x (%s%s%s) ]\n", rtm->rtm_flags,
			colorize_start(bold),
			flags2str(route_flags, rtm->rtm_flags, flags,
				sizeof(flags)),
			colorize_end());

	for (; RTA_OK(attr, attrs_len); attr = RTA_NEXT(attr, attrs_len)) {
		switch (attr->rta_type) {
		case RTA_DST:
			attr_fmt(attr, "Dst %s", addr2str(rtm->rtm_family,
				RTA_DATA(attr), addr_str, sizeof(addr_str)));
			break;
		case RTA_SRC:
			attr_fmt(attr, "Src %s", addr2str(rtm->rtm_family,
				RTA_DATA(attr), addr_str, sizeof(addr_str)));
			break;
		case RTA_IIF:
			attr_fmt(attr, "Iif %d", RTA_INT(attr));
			break;
		case RTA_OIF:
			attr_fmt(attr, "Oif %d", RTA_INT(attr));
			break;
		case RTA_GATEWAY:
			attr_fmt(attr, "Gateway %s", addr2str(rtm->rtm_family,
				RTA_DATA(attr), addr_str, sizeof(addr_str)));
			break;
		case RTA_PRIORITY:
			attr_fmt(attr, "Priority %u", RTA_UINT32(attr));
			break;
		case RTA_PREFSRC:
			attr_fmt(attr, "Pref Src %s", addr2str(rtm->rtm_family,
				RTA_DATA(attr), addr_str, sizeof(addr_str)));
			break;
		case RTA_MARK:
			attr_fmt(attr, "Mark 0x%x", RTA_UINT(attr));
			break;
		case RTA_FLOW:
			attr_fmt(attr, "Flow 0x%x", RTA_UINT(attr));
			break;
		case RTA_TABLE:
			attr_fmt(attr, "Table %d (%s%s%s)", RTA_UINT32(attr),
				colorize_start(bold),
				route_table2str(RTA_UINT32(attr)),
				colorize_end());
			break;
		case RTA_CACHEINFO:
			ci = RTA_DATA(attr);
			tprintf("\tA: Cache (");
			tprintf("expires(%ds)", ci->rta_expires / hz);
			tprintf(", error(%d)", ci->rta_error);
			tprintf(", users(%d)", ci->rta_clntref);
			tprintf(", used(%d)", ci->rta_used);
			tprintf(", last use(%ds)", ci->rta_lastuse / hz);
			tprintf(", id(%d)", ci->rta_id);
			tprintf(", ts(%d)", ci->rta_ts);
			tprintf(", ts age(%ds))", ci->rta_tsage);
			tprintf(", Len %lu\n", RTA_LEN(attr));
			break;
		}
	}
}
Beispiel #9
0
/* Parse one route */
static int rt_parse(const struct nlmsghdr *nlhdr, struct net_rt *rt)
{
	struct rtmsg *rtmsg;
	struct rtattr *rtattr;
	int len;

	rtmsg = (struct rtmsg *)NLMSG_DATA(nlhdr);

	/* If the route does not belong to main routing table then return. */
	if (RT_TABLE_MAIN != rtmsg->rtm_table)
		return EINVAL;

	sa_init(&rt->dst, rtmsg->rtm_family);
	rt->dstlen = rtmsg->rtm_dst_len;

	/* get the rtattr field */
	rtattr = (struct rtattr *)RTM_RTA(rtmsg);
	len = RTM_PAYLOAD(nlhdr);
	for (;RTA_OK(rtattr, len); rtattr = RTA_NEXT(rtattr, len)) {

		switch (rtattr->rta_type) {

		case RTA_OIF:
			if_indextoname(*(int *)RTA_DATA(rtattr), rt->ifname);
			break;

		case RTA_GATEWAY:
			switch (rtmsg->rtm_family) {

			case AF_INET:
				sa_init(&rt->gw, AF_INET);
				rt->gw.u.in.sin_addr.s_addr
					= *(uint32_t *)RTA_DATA(rtattr);
				break;

#ifdef HAVE_INET6
			case AF_INET6:
				sa_set_in6(&rt->gw, RTA_DATA(rtattr), 0);
				break;
#endif

			default:
				DEBUG_WARNING("RTA_DST: unknown family %d\n",
					      rtmsg->rtm_family);
				break;
			}
			break;

#if 0
		case RTA_PREFSRC:
			rt->srcaddr = *(uint32_t *)RTA_DATA(rtattr);
			break;
#endif

		case RTA_DST:
			switch (rtmsg->rtm_family) {

			case AF_INET:
				sa_init(&rt->dst, AF_INET);
				rt->dst.u.in.sin_addr.s_addr
					= *(uint32_t *)RTA_DATA(rtattr);
				break;

#ifdef HAVE_INET6
			case AF_INET6:
				sa_set_in6(&rt->dst, RTA_DATA(rtattr), 0);
				break;
#endif

			default:
				DEBUG_WARNING("RTA_DST: unknown family %d\n",
					      rtmsg->rtm_family);
				break;
			}
			break;
		}
	}

	return 0;
}
Beispiel #10
0
static boolean_t addRoute(route_entry_t *entry) {

    static int skfd = -1;

#if !defined(freebsd8)
    struct rtentry rt;
#else
    struct ortentry rt;
#endif


    if (entry) {

        memset((char *) &rt, 0, sizeof (rt));

        rt.rt_flags |= RTF_UP;

        if (entry->mask == 0xffffffff) {

            rt.rt_flags |= RTF_HOST;

        }

#if !defined(freebsd8)

        rt.rt_metric = 0;

        ((struct sockaddr_in *) &rt.rt_genmask)->sin_addr.s_addr = entry->mask;
        ((struct sockaddr_in *) &rt.rt_genmask)->sin_family = AF_INET;

        if (entry->iface[0] != '\0') {

            rt.rt_dev = entry->iface;

        }

#else


#endif

        ((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr = entry->dst;
        ((struct sockaddr_in *) &rt.rt_dst)->sin_family = AF_INET;

        ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = entry->gateway;
        ((struct sockaddr_in *) &rt.rt_gateway)->sin_family = AF_INET;

        rt.rt_flags |= RTF_GATEWAY;

#if !defined(freebsd8)

        if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
#else
        if ((skfd = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) {
#endif

            DEBUGP(DERROR, "addRoute", "socket: %s", strerror(errno));
            return FALSE;

        }

#if !defined(freebsd8)

        if (ioctl(skfd, SIOCADDRT, &rt) < 0) {

            DEBUGP(DERROR, "addRoute", "ioctl: %s", strerror(errno));
            close(skfd);
            return FALSE;

        }

#else

        struct {
            struct rt_msghdr rtm;
            struct sockaddr addrs[RTAX_MAX];
        } r;

        memset(&r, 0, sizeof (r));

        r.rtm.rtm_version = RTM_VERSION;
        r.rtm.rtm_type = RTM_ADD;
        r.rtm.rtm_pid = getpid();
        r.rtm.rtm_seq = 0;

        struct sockaddr_in dst = {.sin_addr.s_addr = entry->dst, .sin_family = AF_INET, .sin_len = sizeof (struct sockaddr_in)};
        struct sockaddr_in gw = {.sin_addr.s_addr = entry->gateway, .sin_family = AF_INET, .sin_len = sizeof (struct sockaddr_in)};
        struct sockaddr_in mask = {.sin_addr.s_addr = entry->mask, .sin_family = AF_INET, .sin_len = sizeof (struct sockaddr_in)};


        memcpy(&r.addrs[RTAX_DST], &dst, dst.sin_len);
        memcpy(&r.addrs[RTAX_GATEWAY], &gw, gw.sin_len);
        memcpy(&r.addrs[RTAX_NETMASK], &mask, mask.sin_len);

        r.rtm.rtm_addrs = RTA_DST | RTA_GATEWAY;
        r.rtm.rtm_flags = RTF_STATIC | RTF_GATEWAY;
        r.rtm.rtm_msglen = sizeof (r);

        if (entry->mask != 0xffffffff) {

            r.rtm.rtm_addrs |= RTA_NETMASK;

        } else {

            r.rtm.rtm_flags |= (RTF_HOST);

        }

        if (write(skfd, &r, r.rtm.rtm_msglen) != r.rtm.rtm_msglen) {

            DEBUGP(DERROR, "addRoute", "write: %s", strerror(errno));
            close(skfd);
            return FALSE;

        }

#endif

        close(skfd);

        return TRUE;

    }
    return FALSE;

}

static boolean_t delRoute(route_entry_t * entry) {

    static int skfd = -1;

#if !defined(freebsd8)
    struct rtentry rt;
#else
    struct ortentry rt;
#endif


    if (entry) {

        memset((char *) &rt, 0, sizeof (rt));

        rt.rt_flags |= RTF_UP;

        if (entry->mask == 0xffffffff) {

            rt.rt_flags |= RTF_HOST;

        }

#if !defined(freebsd8)

        rt.rt_metric = 0;

        ((struct sockaddr_in *) &rt.rt_genmask)->sin_addr.s_addr = entry->mask;
        ((struct sockaddr_in *) &rt.rt_genmask)->sin_family = AF_INET;

        if (entry->iface[0] != '\0') {

            rt.rt_dev = entry->iface;

        }

#else


#endif

        ((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr = entry->dst;
        ((struct sockaddr_in *) &rt.rt_dst)->sin_family = AF_INET;

        ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = entry->gateway;
        ((struct sockaddr_in *) &rt.rt_gateway)->sin_family = AF_INET;

        rt.rt_flags |= RTF_GATEWAY;

#if !defined(freebsd8)

        if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
#else
        if ((skfd = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) {
#endif

            DEBUGP(DERROR, "delRoute", "socket: %s", strerror(errno));
            return FALSE;

        }

#if !defined(freebsd8)

        if (ioctl(skfd, SIOCDELRT, &rt) < 0) {

            DEBUGP(DERROR, "delRoute", "ioctl: %s", strerror(errno));
            close(skfd);
            return FALSE;

        }

#else

        struct {
            struct rt_msghdr rtm;
            struct sockaddr addrs[RTAX_MAX];
        } r;

        memset(&r, 0, sizeof (r));

        r.rtm.rtm_version = RTM_VERSION;
        r.rtm.rtm_type = RTM_DELETE;
        r.rtm.rtm_pid = getpid();
        r.rtm.rtm_seq = 0;

        struct sockaddr_in dst = {.sin_addr.s_addr = entry->dst, .sin_family = AF_INET, .sin_len = sizeof (struct sockaddr_in)};
        struct sockaddr_in gw = {.sin_addr.s_addr = entry->gateway, .sin_family = AF_INET, .sin_len = sizeof (struct sockaddr_in)};
        struct sockaddr_in mask = {.sin_addr.s_addr = entry->mask, .sin_family = AF_INET, .sin_len = sizeof (struct sockaddr_in)};


        memcpy(&r.addrs[RTAX_DST], &dst, dst.sin_len);
        memcpy(&r.addrs[RTAX_GATEWAY], &gw, gw.sin_len);
        memcpy(&r.addrs[RTAX_NETMASK], &mask, mask.sin_len);

        r.rtm.rtm_addrs = RTA_DST | RTA_GATEWAY;
        r.rtm.rtm_flags = RTF_DONE;
        r.rtm.rtm_msglen = sizeof (r);

        if (entry->mask != 0xffffffff) {

            r.rtm.rtm_addrs |= RTA_NETMASK;

        } else {

            r.rtm.rtm_flags |= (RTF_HOST);

        }

        if (write(skfd, &r, r.rtm.rtm_msglen) != r.rtm.rtm_msglen) {

            DEBUGP(DERROR, "delRoute", "write: %s", strerror(errno));
            close(skfd);
            return FALSE;

        }

#endif

        close(skfd);

        return TRUE;

    }
    return FALSE;

}

static list_t *routeLookup(route_entry_t *key) {

    list_t *result = NULL;
    int skfd = -1;

    if (key) {

#ifdef freebsd8

        struct ortentry rt;

        memset((char *) &rt, 0, sizeof (rt));

        rt.rt_flags |= RTF_UP;

        if (key->mask == 0xffffffff) {

            rt.rt_flags |= RTF_HOST;

        }

        rt.rt_flags |= RTF_GATEWAY;

        if ((skfd = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) {

            DEBUGP(DERROR, "routeLookup", "socket: %s", strerror(errno));
            return result;

        }

        struct {
            struct rt_msghdr rtm;
            struct sockaddr addrs[RTAX_MAX];
        } r;

        memset(&r, 0, sizeof (r));

        r.rtm.rtm_version = RTM_VERSION;
        r.rtm.rtm_type = RTM_GET;
        r.rtm.rtm_pid = getpid();
        r.rtm.rtm_seq = 0;

        struct sockaddr_in dst = {.sin_addr.s_addr = key->dst, .sin_family = AF_INET, .sin_len = sizeof (struct sockaddr_in)};
        struct sockaddr_in mask = {.sin_addr.s_addr = key->mask, .sin_family = AF_INET, .sin_len = sizeof (struct sockaddr_in)};


        memcpy(&r.addrs[RTAX_DST], &dst, dst.sin_len);
        memcpy(&r.addrs[RTAX_NETMASK], &mask, mask.sin_len);

        r.rtm.rtm_addrs = RTA_DST;
        r.rtm.rtm_flags = RTF_DONE;
        r.rtm.rtm_msglen = sizeof (r);

        if (key->mask != 0xffffffff) {

            r.rtm.rtm_addrs |= RTA_NETMASK;

        } else {

            r.rtm.rtm_flags |= (RTF_HOST);

        }

        if (write(skfd, &r, r.rtm.rtm_msglen) != r.rtm.rtm_msglen) {

            DEBUGP(DERROR, "routeLookup", "write: %s", strerror(errno));
            close(skfd);
            return result;

        }

        result = I(List)->new();

        while (1) {


            if (read(skfd, (struct rt_msghdr *) &r, sizeof (r)) < 0) {

                DEBUGP(DERROR, "routeLookup", "read: %s", strerror(errno));
                close(skfd);
                break;

            }

            route_entry_t *e = calloc(1, sizeof (route_entry_t));

            e->gateway = ((struct sockaddr_in*) &r.addrs[RTAX_GATEWAY])->sin_addr.s_addr;

            I(List)->insert(result, I(ListItem)->new(e));

            if (r.rtm.rtm_flags & RTF_DONE) {

                break;

            }

        }

#endif

#ifdef linux

        struct {
            struct nlmsghdr n;
            struct rtmsg r;
            char buf[1024];
        } req;

        struct nhop {
            in_addr_t gw;
            char dev[IFNAMSIZ];
        };

        list_t *nhops = NULL;

        struct nlmsghdr *h;
        struct rtmsg *rtmp;
        struct rtattr *rtatp;
        int rtattrlen;
        int rval = -1;
        char buf[4096];
        char dev[IFNAMSIZ];
        in_addr_t src = 0;
        in_addr_t dst = 0;
        in_addr_t mask = 0;
        in_addr_t gw = 0;

        if ((skfd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE)) < 0) {

            DEBUGP(DERROR, "routeLookup", "socket: %s", strerror(errno));
            return FALSE;

        }

        memset(&req, 0, sizeof (req));
        req.n.nlmsg_len = NLMSG_LENGTH(sizeof (struct rtmsg));
        req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
        req.n.nlmsg_type = RTM_GETROUTE;
        req.n.nlmsg_len = NLMSG_ALIGN(req.n.nlmsg_len);

        if (send(skfd, &req, req.n.nlmsg_len, 0) < 0) {

            DEBUGP(DERROR, "routeLookup", "send: %s", strerror(errno));
            close(skfd);
            return result;

        }

        if ((rval = recv(skfd, buf, sizeof (buf), 0)) < 0) {

            DEBUGP(DERROR, "routeLookup", "recv: %s", strerror(errno));
            close(skfd);
            return result;

        }

        for (h = (struct nlmsghdr *) buf; NLMSG_OK(h, rval); h = NLMSG_NEXT(h, rval)) {

            rtmp = (struct rtmsg *) NLMSG_DATA(h);
            rtatp = (struct rtattr *) RTM_RTA(rtmp);
            rtattrlen = RTM_PAYLOAD(h);

            src = 0;
            dst = 0;
            mask = 0;
            gw = 0;


            if (result == NULL) {

                result = I(List)->new();

            }

            for (; RTA_OK(rtatp, rtattrlen); rtatp = RTA_NEXT(rtatp, rtattrlen)) {

                switch (rtatp->rta_type) {

                    case RTA_OIF:
                    {
                        int oif_index = *(int *) RTA_DATA(rtatp);

                        if_indextoname(oif_index, dev);
                        break;
                    }

                    case RTA_PREFSRC: src = *((in_addr_t *) RTA_DATA(rtatp));
                        break;
                    case RTA_DST: dst = *((in_addr_t *) RTA_DATA(rtatp));
                        mask = rtmp->rtm_dst_len != 0 ? htonl(~0 << (32 - rtmp->rtm_dst_len)) : 0;
                        break;
                    case RTA_GATEWAY: gw = *((in_addr_t *) RTA_DATA(rtatp));
                        break;

                    case RTA_MULTIPATH:
                    {

                        nhops = I(List)->new();

                        struct rtnexthop *nh = NULL;
                        
                        struct rtattr *nhrtattr = NULL;
                        int nh_len = RTA_PAYLOAD(rtatp);

                        for (nh = RTA_DATA(rtatp); RTNH_OK(nh, nh_len); nh = RTNH_NEXT(nh)) {

                            struct nhop *hop = calloc(1, sizeof (struct nhop));

                            int attr_len = nh->rtnh_len - sizeof (*nh);

                            if (nh_len < sizeof (*nh))
                                break;
                            if (nh->rtnh_len > nh_len)
                                break;

                            if (nh->rtnh_len > sizeof (*nh)) {

                                if_indextoname(nh->rtnh_ifindex, hop->dev);

                                for (nhrtattr = RTNH_DATA(nh); RTA_OK(nhrtattr, attr_len); nhrtattr = RTA_NEXT(nhrtattr, attr_len)) {

                                    switch (nhrtattr->rta_type) {

                                        case RTA_GATEWAY:
                                            hop->gw = *((in_addr_t *) RTA_DATA(nhrtattr));
                                            break;


                                    }

                                }

                                I(List)->insert(nhops, I(ListItem)->new(hop));

                            }

                            nh_len -= NLMSG_ALIGN(nh->rtnh_len);
                        }

                        break;
                    }

                }

            }

            if (nhops == NULL) {

                if (key && ((key->dst != dst) || (key->iface[0] != '\0' && strcmp(key->iface, dev) != 0))) {

                    continue;

                }

                route_entry_t *r = calloc(1, sizeof (route_entry_t));

                r->gateway = gw;
                r->mask = mask;
                r->dst = dst;
                r->src = src;
                strcpy(r->iface, dev);

                I(List)->insert(result, I(ListItem)->new(r));

            } else {

                struct nhop *h = NULL;
                list_item_t *item = NULL;

                while (item = I(List)->pop(nhops)) {

                    h = item->data;

                    if (key && ((key->dst != dst) || (key->iface[0] != '\0' && strcmp(key->iface, h->dev) != 0))) {

                        I(ListItem)->destroy(&item);
                        free(h);
                        continue;

                    }

                    route_entry_t *r = calloc(1, sizeof (route_entry_t));

                    r->gateway = h->gw;
                    r->mask = mask;
                    r->dst = dst;
                    r->src = src;
                    strcpy(r->iface, h->dev);

                    I(List)->insert(result, I(ListItem)->new(r));
                    I(ListItem)->destroy(&item);
                    free(h);

                }

                I(List)->destroy(&nhops);

            }

        }

#endif

        close(skfd);

        return result;

    }

    return result;

}

static list_t * cacheLookup(route_entry_t * dest) {

    list_t *result = NULL;

#if defined(linux)

    FILE *f = fopen("/proc/net/rt_cache", "r");

    if (f) {

        char buf[512];

        result = I(List)->new();

        fgets(buf, sizeof (buf), f); // skip header

        while (!feof(f)) {

            if (fgets(buf, sizeof (buf), f)) {

                list_t *fields = I(String)->tokenize(buf, "\t");

                int i = 0;
                list_item_t *item;

                route_entry_t *entry = calloc(1, sizeof (route_entry_t));

                while ((item = I(List)->pop(fields))) {

                    switch (i) {

                        case 0: strcpy(entry->iface, (char*) item->data);
                            break;
                        case 1: sscanf((char*) item->data, "%X", &entry->dst);
                            break;
                        case 2: sscanf((char*) item->data, "%X", &entry->gateway);
                            break;
                        case 7: sscanf((char*) item->data, "%X", &entry->src);
                            break;

                    }

                    free(item->data);
                    I(ListItem)->destroy(&item);
                    i++;

                }

                I(List)->destroy(&fields);

                if (dest) {

                    if (dest->dst && dest->dst != entry->dst) {

                        free(entry);
                        continue;

                    }

                }

                I(List)->insert(result, I(ListItem)->new(entry));


            }

        }

        fclose(f);

    }

#endif

    return result;

}

static boolean_t addHostRoute(in_addr_t dst, in_addr_t gw, char *iface) {

    route_entry_t route = {.dst = dst, .src = 0, .gateway = gw, .mask = 0xffffffff};
    boolean_t result = FALSE;

    if (iface)
        strcpy(route.iface, iface);
    else
        route.iface[0] = '\0';

    result = addRoute(&route);

    return result;

}

static boolean_t delHostRoute(in_addr_t dst, in_addr_t gw, char *iface) {

    route_entry_t route = {.dst = dst, .src = 0, .gateway = gw, .mask = 0xffffffff};
    boolean_t result = FALSE;

    if (iface)
        strcpy(route.iface, iface);
    else
        route.iface[0] = '\0';

    result = delRoute(&route);

    return result;

}

static in_addr_t getIfIP(char *iface) {

    in_addr_t result = 0;

    if (iface) {

        struct ifreq req;
        int sock = socket(AF_INET, SOCK_DGRAM, 0);

        memset(&req, 0, sizeof (struct ifreq));
        strcpy(req.ifr_name, iface);

        if (ioctl(sock, SIOCGIFADDR, &req) >= 0) {

            result = ((struct sockaddr_in *) &req.ifr_addr)->sin_addr.s_addr;

        } else {

            DEBUGP(DERROR, "getIfIP", "ioctl: %s", strerror(errno));

        }

        close(sock);

    }

    return result;

}

static in_addr_t getIfGW(char *iface) {

    route_entry_t route = {.dst = 0, .src = 0, .gateway = 0, .mask = 0};
    list_t *routes = NULL;
    in_addr_t result = 0;

    if (iface)
        strcpy(route.iface, iface);
    else
        route.iface[0] = '\0';

    routes = routeLookup(&route);

    if (routes) {

        if (I(List)->count(routes) > 0) {

            list_item_t *e = I(List)->pop(routes);
            route_entry_t *entry = (route_entry_t *) e->data;

            result = entry->gateway;

            free(entry);
            I(ListItem)->destroy(&e);

        }

        I(List)->clear(routes, TRUE);
        I(List)->destroy(&routes);

    }

    return result;

}

IMPLEMENT_INTERFACE(Route) = {

    .addRoute = addRoute,
    .delRoute = delRoute,
    .cacheLookup = cacheLookup,
    .addHostRoute = addHostRoute,
    .delHostRoute = delHostRoute,
    .getIfGW = getIfGW,
    .getIfIP = getIfIP

};
Beispiel #11
0
__static void
pflnet_getifnfordst_rtnetlink(const struct sockaddr *sa,
    char ifn[IFNAMSIZ])
{
	struct {
		struct nlmsghdr	nmh;
		struct rtmsg	rtm;
#define RT_SPACE 8192
		unsigned char	buf[RT_SPACE];
	} rq;
	const struct sockaddr_in *sin;
	struct nlmsghdr *nmh;
	struct rtattr *rta;
	struct rtmsg *rtm;
	ssize_t rc, rca;
	int s, ifidx;
	size_t nb;

	sin = (void *)sa;

	s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
	if (s == -1)
		psc_fatal("socket");

	memset(&rq, 0, sizeof(rq));
	rq.nmh.nlmsg_len = NLMSG_SPACE(sizeof(rq.rtm)) +
	    RTA_LENGTH(sizeof(sin->sin_addr));
	rq.nmh.nlmsg_flags = NLM_F_REQUEST;
	rq.nmh.nlmsg_type = RTM_GETROUTE;

	rq.rtm.rtm_family = sa->sa_family;
	rq.rtm.rtm_protocol = RTPROT_UNSPEC;
	rq.rtm.rtm_table = RT_TABLE_MAIN;
	/* # bits filled in target addr */
	rq.rtm.rtm_dst_len = sizeof(sin->sin_addr) * NBBY;
	rq.rtm.rtm_scope = RT_SCOPE_LINK;

	rta = (void *)((char *)&rq + NLMSG_SPACE(sizeof(rq.rtm)));
	rta->rta_type = RTA_DST;
	rta->rta_len = RTA_LENGTH(sizeof(sin->sin_addr));
	memcpy(RTA_DATA(rta), &sin->sin_addr,
	    sizeof(sin->sin_addr));

	errno = 0;
	rc = write(s, &rq, rq.nmh.nlmsg_len);
	if (rc != (ssize_t)rq.nmh.nlmsg_len)
		psc_fatal("routing socket length mismatch");

	rc = read(s, &rq, sizeof(rq));
	if (rc == -1)
		psc_fatal("routing socket read");
	close(s);

	switch (rq.nmh.nlmsg_type) {
	case NLMSG_ERROR: {
		struct nlmsgerr *nlerr;

		nlerr = NLMSG_DATA(&rq.nmh);
		psc_fatalx("netlink: %s", strerror(nlerr->error));
	    }
	case NLMSG_DONE:
		psc_fatalx("netlink: unexpected EOF");
	}

	nmh = &rq.nmh;
	nb = rc;
	for (; NLMSG_OK(nmh, nb); nmh = NLMSG_NEXT(nmh, nb)) {
		rtm = NLMSG_DATA(nmh);

		if (rtm->rtm_table != RT_TABLE_MAIN)
			continue;

		rta = RTM_RTA(rtm);
		rca = RTM_PAYLOAD(nmh);

		for (; RTA_OK(rta, rca); rta = RTA_NEXT(rta, rca)) {
			switch (rta->rta_type) {
			case RTA_OIF:
				memcpy(&ifidx, RTA_DATA(rta),
				    sizeof(ifidx));
				pflnet_getifname(ifidx, ifn);
				return;
			}
		}
	}
	psc_fatalx("no route for addr");
}
Beispiel #12
0
__static int
pflnet_rtexists_rtnetlink(const struct sockaddr *sa)
{
	struct {
		struct nlmsghdr	nmh;
		struct rtmsg	rtm;
#define RT_SPACE 8192
		unsigned char	buf[RT_SPACE];
		struct rtattr	rta;
		struct nlmsgerr	nlerr;
	} rq;
	struct sockaddr_in *sin = (void *)sa;
	in_addr_t cmpaddr, zero = 0;
	struct nlmsghdr *nmh;
	struct rtattr *rta;
	struct rtmsg *rtm;
	ssize_t rc, rca;
	int rv = 0, s;
	size_t nb;

	s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
	if (s == -1)
		psc_fatal("socket");

	memset(&rq, 0, sizeof(rq));
	rq.nmh.nlmsg_len = NLMSG_SPACE(sizeof(rq.rtm));
	rq.nmh.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
	rq.nmh.nlmsg_type = RTM_GETROUTE;

	rq.rtm.rtm_family = sa->sa_family;
	rq.rtm.rtm_protocol = RTPROT_UNSPEC;
	rq.rtm.rtm_table = RT_TABLE_MAIN;
	rq.rtm.rtm_scope = RT_SCOPE_LINK;

	rta = (void *)((char *)&rq.rta + NLMSG_SPACE(sizeof(rq.rtm)));
	rta->rta_type = RTA_DST;
	rta->rta_len = RTA_LENGTH(sizeof(sin->sin_addr));
	memcpy(RTA_DATA(rta), &sin->sin_addr,
	    sizeof(sin->sin_addr));

	errno = 0;
	rc = write(s, &rq, rq.nmh.nlmsg_len);
	if (rc != (ssize_t)rq.nmh.nlmsg_len)
		psc_fatal("routing socket length mismatch");

	for (;;) {
		rc = read(s, &rq, sizeof(rq));
		if (rc == -1)
			psc_fatal("routing socket read");

		switch (rq.nmh.nlmsg_type) {
		case NLMSG_ERROR: {
			struct nlmsgerr *nlerr;

			nlerr = NLMSG_DATA(&rq.nlerr);
			psc_fatalx("netlink: %s", strerror(nlerr->error));
		    }
		case NLMSG_DONE:
			goto out;
		}

		nmh = &rq.nmh;
		nb = rc;
		for (; NLMSG_OK(nmh, nb); nmh = NLMSG_NEXT(nmh, nb)) {
			rtm = NLMSG_DATA(nmh);

			if (rtm->rtm_table != RT_TABLE_MAIN)
				continue;

			rta = RTM_RTA(rtm);
			rca = RTM_PAYLOAD(nmh);

			for (; RTA_OK(rta, rca);
			    rta = RTA_NEXT(rta, rca)) {
				switch (rta->rta_type) {
				case RTA_GATEWAY:
					cmpaddr = sin->sin_addr.s_addr;
					if (zero == cmpaddr) {
						rv = 1;
						goto out;
					}
					break;
				case RTA_DST:
					cmpaddr = sin->sin_addr.s_addr;

					pfl_bitstr_copy(&cmpaddr,
					    rtm->rtm_dst_len, &zero, 0,
					    sizeof(zero) * NBBY -
					    rtm->rtm_dst_len);

					if (cmpaddr == *(in_addr_t *)
					    RTA_DATA(rta)) {
						rv = 1;
						goto out;
					}
					break;
				}
			}
		}
	}
 out:
	close(s);
	return (rv);
}
Beispiel #13
0
/*
 * parse route message
 */
int parse_rtmsg(struct nlmsghdr *nlh)
{
    struct rtmsg *rtm;
    int rtm_len;
    struct rtattr *rta[__RTA_MAX];
    char ipv[MAX_STR_SIZE] = "";
    char msg[MAX_MSG_SIZE] = "";
    char *mp = msg;
    int log_opts = get_log_opts();
    int res;

    /* debug nlmsghdr */
    if(log_opts & L_DEBUG)
        debug_nlmsg(0, nlh);

    /* get rtmsg */
    rtm_len = NLMSG_PAYLOAD(nlh, 0);
    if(rtm_len < sizeof(*rtm)) {
        rec_log("error: %s: rtmsg: length too short", __func__);
        return(1);
    }
    rtm = (struct rtmsg *)NLMSG_DATA(nlh);

    /* parse route attributes */
    parse_rtattr(rta, RTA_MAX, RTM_RTA(rtm), RTM_PAYLOAD(nlh));

    /* debug rtmsg */
    if(log_opts & L_DEBUG)
        debug_rtmsg(0, rtm, rta, rtm_len);

    /* check address family */
    char dst[INET6_ADDRSTRLEN] = "";
    if(rtm->rtm_family == AF_INET) {
        strcpy(ipv, "ipv4");
        strcpy(dst, "0.0.0.0");
    } else if(rtm->rtm_family == AF_INET6) {
        strcpy(ipv, "ipv6");
        strcpy(dst, "::");
    } else {
        rec_log("error: %s: unknown address family: %d",
                __func__, rtm->rtm_family);
        return(1);
    }

    /* convert from table id to table name */
    char table[MAX_STR_SIZE] = "";
    snprintf(table, sizeof(table), "%s", conv_rt_table(rtm->rtm_table, 0));
    if(!strncmp(table, "unknown", sizeof(table)))
        snprintf(table, sizeof(table), "%d", rtm->rtm_table);

    /* check route table id(other than RT_TABLE_LOCAL) */
    if(rtm->rtm_table == RT_TABLE_LOCAL)
        return(1);

    /* check route protocol(other than RTPROT_UNSPEC) */
    if(rtm->rtm_protocol == RTPROT_UNSPEC)
        return(1);
    
    /* check route flags(other then RTM_F_CLONED) */
    if(rtm->rtm_flags & RTM_F_CLONED)
        return(1);

    /* get destination prefix */
    if(rta[RTA_DST]) {
        res = inet_ntop_ifa(rtm->rtm_family, rta[RTA_DST], dst, sizeof(dst));
        if(res) {
            rec_log("error: %s: RTA_DST: %s", __func__,
                (res == 1) ? strerror(errno) : "payload too short");
            return(1);
        }
    }
    /* no RTA_DST attribute if destination is a default gateway */
    mp = add_log(msg, mp, "destination=%s/%d ", dst, rtm->rtm_dst_len);

    /* get source prefix */
    if(rta[RTA_SRC]) {
        char src[INET6_ADDRSTRLEN] = "";

        res = inet_ntop_ifa(rtm->rtm_family, rta[RTA_SRC], src, sizeof(src));
        if(res == 1) {
            rec_log("error: %s: RTA_SRC: %s", __func__,
                (res == 1) ? strerror(errno) : "payload too short");
            return(1);
        }
        mp = add_log(msg, mp, "source=%s/%d ", src, rtm->rtm_src_len);
    }

    /* get preferred source address */
    if(rta[RTA_PREFSRC]) {
        char prefsrc[INET6_ADDRSTRLEN] = "";

        res = inet_ntop_ifa(rtm->rtm_family, rta[RTA_PREFSRC], prefsrc, sizeof(prefsrc));
        if(res) {
            rec_log("error: %s: RTA_PREFSRC: %s", __func__,
                (res == 1) ? strerror(errno) : "payload too short");
            return(1);
        }
        mp = add_log(msg, mp, "preferred-source=%s ", prefsrc);
    }

    /* get tos */
    if(rtm->rtm_tos)
        mp = add_log(msg, mp, "tos=0x%.2x ", rtm->rtm_tos);

    /* get ingress interface */
    if(rta[RTA_IIF]) {
        unsigned iifindex;
        char iifname[IFNAMSIZ] = "";

        if(RTA_PAYLOAD(rta[RTA_IIF]) < sizeof(iifindex)) {
            rec_log("error: %s: RTA_IIF: payload too short", __func__);
            return(1);
        }
        iifindex = *((unsigned *)RTA_DATA(rta[RTA_IIF]));
        if_indextoname_from_lists(iifindex, iifname);

        mp = add_log(msg, mp, "in=%s ", iifname);
    }

    /* get gateway address */
    if(rta[RTA_GATEWAY]) {
        char nexthop[INET6_ADDRSTRLEN] = "";

        res = inet_ntop_ifa(rtm->rtm_family, rta[RTA_GATEWAY], nexthop, sizeof(nexthop));
        if(res) {
            rec_log("error: %s: RTA_GATEWAY: %s", __func__,
                (res == 1) ? strerror(errno) : "payload too short");
            return(1);
        }
        mp = add_log(msg, mp, "nexthop=%s ", nexthop);
    }

    /* get egress interface */
    if(rta[RTA_OIF]) {
        unsigned oifindex;
        char oifname[IFNAMSIZ] = "";

        if(RTA_PAYLOAD(rta[RTA_OIF]) < sizeof(oifindex)) {
            rec_log("error: %s: RTA_OIF: payload too short", __func__);
            return(1);
        }
        oifindex = *((unsigned *)RTA_DATA(rta[RTA_OIF]));
        if_indextoname_from_lists(oifindex, oifname);

        mp = add_log(msg, mp, "interface=%s ", oifname);
    }

    /* get priority(but metric) */
    char metric[MAX_STR_SIZE] = "";
    if(rta[RTA_PRIORITY]) {
        if(RTA_PAYLOAD(rta[RTA_PRIORITY]) < sizeof(int)) {
            rec_log("error: %s: RTA_PRIORITY: payload too short", __func__);
            return(1);
        }
        snprintf(metric, sizeof(metric), "metric=%d ", *((int *)RTA_DATA(rta[RTA_PRIORITY])));
    }

    /* convert route message type */
    char type[MAX_STR_SIZE] = "";
    snprintf(type, sizeof(type), "%s", conv_rtn_type(rtm->rtm_type, 0));

    /* convert route message protocol */
    char proto[MAX_STR_SIZE] = "";
    snprintf(proto, sizeof(proto), "%s", conv_rtprot(rtm->rtm_protocol, 0));

    /* get table id & name */
    if(rta[RTA_TABLE]) {
        int table_id = *(int *)RTA_DATA(rta[RTA_TABLE]);

        if(RTA_PAYLOAD(rta[RTA_TABLE]) < sizeof(int)) {
            rec_log("error: %s: RTA_TABLE: payload too short", __func__);
            return(1);
        }
        snprintf(table, sizeof(table), "%s", conv_rt_table(table_id, 0));
        if(!strncmp(table, "unknown", sizeof(table)))
            snprintf(table, sizeof(table), "%d", table_id);
    }

    /* get multipath */
    if(rta[RTA_MULTIPATH]) {
        struct rtnexthop *rtnh;
        int rtnh_len = RTA_PAYLOAD(rta[RTA_MULTIPATH]);
        struct rtattr *rtna[__RTA_MAX];
        char rtnh_ifname[IFNAMSIZ] = "";
        char rtnh_nexthop[INET6_ADDRSTRLEN] = "";

        if(RTA_PAYLOAD(rta[RTA_MULTIPATH]) < sizeof(*rtnh)) {
            rec_log("error: %s: RTA_MULTIPATH: payload too short", __func__);
            return(1);
        }
        rtnh = RTA_DATA(rta[RTA_MULTIPATH]);

        for(; RTNH_OK(rtnh, rtnh_len);
            rtnh = RTNH_NEXT(rtnh), rtnh_len -= RTNH_ALIGN(rtnh->rtnh_len)) {
            parse_rtattr(rtna, RTA_MAX, RTNH_DATA(rtnh), rtnh->rtnh_len - sizeof(*rtnh));

            if(rtna[RTA_GATEWAY]) {
                res = inet_ntop_ifa(rtm->rtm_family, rtna[RTA_GATEWAY],
                    rtnh_nexthop, sizeof(rtnh_nexthop));
                if(res) {
                    rec_log("error: %s: RTA_GATEWAY: %s", __func__,
                        (res == 1) ? strerror(errno) : "payload too short");
                    return(1);
                }
            }

            /* get interface name & logging routing table message */
            if_indextoname_from_lists(rtnh->rtnh_ifindex, rtnh_ifname);
            if(nlh->nlmsg_type == RTM_NEWROUTE)
                rec_log("%s route added: %snexthop=%s interface=%s "
                    "%sweight=%d type=%s protocol=%s table=%s",
                    ipv, msg, rtnh_nexthop, rtnh_ifname,
                    metric, rtnh->rtnh_hops+1, type, proto, table);
            else if(nlh->nlmsg_type == RTM_DELROUTE)
                rec_log("%s route deleted: %snexthop=%s interface=%s " 
                    "%sweight=%d type=%s protocol=%s table=%s",
                    ipv, msg, rtnh_nexthop, rtnh_ifname,
                    metric, rtnh->rtnh_hops+1, type, proto, table);
        }

        return(0);
    }

    /* logging routing message */
    if(nlh->nlmsg_type == RTM_NEWROUTE)
        rec_log("%s route added: %s%stype=%s protocol=%s table=%s",
            ipv, msg, metric, type, proto, table);
    else if(nlh->nlmsg_type == RTM_DELROUTE)
        rec_log("%s route deleted: %s%stype=%s proto=%s table=%s",
            ipv, msg, metric, type, proto, table);

    return(0);
}
Beispiel #14
0
int get_hw_addr(struct in_addr *gw_ip, char *iface, unsigned char *hw_mac)
{
	char buf[8192];
	struct ndmsg req;
	struct nlmsghdr *nlhdr;

	if (!gw_ip || !hw_mac) {
		return -1;
	}
	// Send RTM_GETNEIGH request
	req.ndm_family = AF_INET;
	req.ndm_ifindex = if_nametoindex(iface);
	req.ndm_state = NUD_REACHABLE;
	req.ndm_type = NDA_LLADDR;

	int sock = send_nl_req(RTM_GETNEIGH, 1, &req, sizeof(req));

	// Read responses
	unsigned nl_len = read_nl_sock(sock, buf, sizeof(buf));
	if (nl_len <= 0) {
		return -1;
	}
	// Parse responses
	nlhdr = (struct nlmsghdr *)buf;
	while (NLMSG_OK(nlhdr, nl_len)) {
		struct rtattr *rt_attr;
		struct rtmsg *rt_msg;
		int rt_len;
		unsigned char mac[6];
		struct in_addr dst_ip;
		int correct_ip = 0;

		rt_msg = (struct rtmsg *) NLMSG_DATA(nlhdr);
		
		if ((rt_msg->rtm_family != AF_INET)) {
			return -1;
		}
	
		rt_attr = (struct rtattr *) RTM_RTA(rt_msg);
		rt_len = RTM_PAYLOAD(nlhdr);
		while (RTA_OK(rt_attr, rt_len)) {
			switch (rt_attr->rta_type) {
			case NDA_LLADDR: 
				assert(RTA_PAYLOAD(rt_attr) == IFHWADDRLEN);
				memcpy(mac, RTA_DATA(rt_attr), IFHWADDRLEN);
				break;
			case NDA_DST:
				assert(RTA_PAYLOAD(rt_attr) == sizeof(dst_ip));
				memcpy(&dst_ip, RTA_DATA(rt_attr), sizeof(dst_ip));
				if (memcmp(&dst_ip, gw_ip, sizeof(dst_ip)) == 0) {
					correct_ip = 1;
				}
				break;
			}
			rt_attr = RTA_NEXT(rt_attr, rt_len);
		}
		if (correct_ip) {
			memcpy(hw_mac, mac, IFHWADDRLEN);
			return 0;
		}
		nlhdr = NLMSG_NEXT(nlhdr, nl_len);	
	}
	return -1;				
}
Beispiel #15
0
static struct ether_addr *resolve_mac_from_cache(int ai_family,
						 const void *l3addr)
{
	uint8_t l3addr_tmp[16];
	static struct ether_addr mac_tmp;
	struct ether_addr *mac_result = NULL;
	void *buf = NULL;
	size_t buflen;
	struct nlmsghdr *nh;
	ssize_t len;
	size_t l3_len, mlen;
	int socknl;
	int parsed;
	int finished = 0;

	switch (ai_family) {
	case AF_INET:
		l3_len = 4;
		break;
	case AF_INET6:
		l3_len = 16;
		break;
	default:
		l3_len = 0;
	}

	buflen = 8192;
	buf = malloc(buflen);
	if (!buf)
		goto err;

	socknl = resolve_mac_from_cache_open(ai_family);
	if (socknl < 0)
		goto err;


	while (!finished) {
		len = resolve_mac_from_cache_dump(socknl, &buf, &buflen);
		if (len < 0)
			goto err_sock;
		mlen = len;

		for (nh = buf; NLMSG_OK(nh, mlen); nh = NLMSG_NEXT(nh, mlen)) {
			if (nh->nlmsg_type == NLMSG_DONE) {
				finished = 1;
				break;
			}

			parsed = resolve_mac_from_cache_parse(NLMSG_DATA(nh),
							      RTM_PAYLOAD(nh),
							      &mac_tmp,
							      l3addr_tmp,
							      l3_len);
			if (parsed) {
				if (memcmp(&l3addr_tmp, l3addr, l3_len) == 0) {
					mac_result = &mac_tmp;
					finished = 1;
					break;
				}
			}
		}
	}

err_sock:
	close(socknl);
err:
	free(buf);
	return mac_result;
}
Beispiel #16
0
/**
 * Scan netlink message in the buffer for IPv6 default route changes.
 */
static int
rtmon_check_defaults(const void *buf, size_t len)
{
    struct nlmsghdr *nh;
    int dfltdiff = 0;

    for (nh = (struct nlmsghdr *)buf;
         NLMSG_OK(nh, len);
         nh = NLMSG_NEXT(nh, len))
    {
        struct rtmsg *rtm;
        struct rtattr *rta;
        int attrlen;
        int delta = 0;
        const void *gwbuf;
        size_t gwlen;
        int oif;

        DPRINTF2(("nlmsg type %d flags 0x%x\n",
                  nh->nlmsg_seq, nh->nlmsg_type, nh->nlmsg_flags));

        if (nh->nlmsg_type == NLMSG_DONE) {
            break;
        }

        if (nh->nlmsg_type == NLMSG_ERROR) {
            struct nlmsgerr *ne = (struct nlmsgerr *)NLMSG_DATA(nh);
            DPRINTF2(("> error %d\n", ne->error));
            LWIP_UNUSED_ARG(ne);
            break;
        }

        if (nh->nlmsg_type < RTM_BASE || RTM_MAX <= nh->nlmsg_type) {
            /* shouldn't happen */
            DPRINTF2(("> not an RTM message!\n"));
            continue;
        }


        rtm = (struct rtmsg *)NLMSG_DATA(nh);
        attrlen = RTM_PAYLOAD(nh);

        if (nh->nlmsg_type == RTM_NEWROUTE) {
            delta = +1;
        }
        else if (nh->nlmsg_type == RTM_DELROUTE) {
            delta = -1;
        }
        else {
            /* shouldn't happen */
            continue;
        }

        /*
         * Is this an IPv6 default route in the main table?  (Local
         * table always has ::/0 reject route, hence the last check).
         */
        if (rtm->rtm_family == AF_INET6 /* should always be true */
            && rtm->rtm_dst_len == 0
            && rtm->rtm_table == RT_TABLE_MAIN)
        {
            dfltdiff += delta;
        }
        else {
            /* some other route change */
            continue;
        }


        gwbuf = NULL;
        gwlen = 0;
        oif = -1;

        for (rta = RTM_RTA(rtm);
             RTA_OK(rta, attrlen);
             rta = RTA_NEXT(rta, attrlen))
        {
            if (rta->rta_type == RTA_GATEWAY) {
                gwbuf = RTA_DATA(rta);
                gwlen = RTA_PAYLOAD(rta);
            }
            else if (rta->rta_type == RTA_OIF) {
                /* assert RTA_PAYLOAD(rta) == 4 */
                memcpy(&oif, RTA_DATA(rta), sizeof(oif));
            }
        }

        /* XXX: TODO: note that { oif, gw } was added/removed */
        LWIP_UNUSED_ARG(gwbuf);
        LWIP_UNUSED_ARG(gwlen);
        LWIP_UNUSED_ARG(oif);
    }

    return dfltdiff;
}
Beispiel #17
0
static int netlink_receive(struct netlink_fd *fd, struct nlmsghdr *reply)
{
	struct sockaddr_nl nladdr;
	struct iovec iov;
	struct msghdr msg = {
		.msg_name = &nladdr,
		.msg_namelen = sizeof(nladdr),
		.msg_iov = &iov,
		.msg_iovlen = 1,
	};
	int got_reply = FALSE, len;
	char buf[16*1024];

	iov.iov_base = buf;
	while (!got_reply) {
		int status;
		struct nlmsghdr *h;

		iov.iov_len = sizeof(buf);
		status = recvmsg(fd->fd, &msg, MSG_DONTWAIT);
		if (status < 0) {
			if (errno == EINTR)
				continue;
			if (errno == EAGAIN)
				return reply == NULL;
			fprintf(stderr, "Netlink overrun\n");
			continue;
		}

		if (status == 0) {
			fprintf(stderr, "Netlink returned EOF\n");
			return FALSE;
		}

		h = (struct nlmsghdr *) buf;
		while (NLMSG_OK(h, status)) {
			if (reply != NULL &&
			    h->nlmsg_seq == reply->nlmsg_seq) {
				len = h->nlmsg_len;
				if (len > reply->nlmsg_len) {
					fprintf(stderr, "Netlink message "
						"truncated\n");
					len = reply->nlmsg_len;
				}
				memcpy(reply, h, len);
				got_reply = TRUE;
			} else if (h->nlmsg_type != NLMSG_DONE) {
				fprintf(stderr,
					"Unknown NLmsg: 0x%08x, len %d\n",
					h->nlmsg_type, h->nlmsg_len);
			}
			h = NLMSG_NEXT(h, status);
		}
	}

	return TRUE;
}

static int netlink_send(struct netlink_fd *fd, struct nlmsghdr *req)
{
	struct sockaddr_nl nladdr;
	struct iovec iov = {
		.iov_base = (void*) req,
		.iov_len = req->nlmsg_len
	};
	struct msghdr msg = {
		.msg_name = &nladdr,
		.msg_namelen = sizeof(nladdr),
		.msg_iov = &iov,
		.msg_iovlen = 1,
	};
	int status;

	memset(&nladdr, 0, sizeof(nladdr));
	nladdr.nl_family = AF_NETLINK;

	req->nlmsg_seq = ++fd->seq;

	status = sendmsg(fd->fd, &msg, 0);
	if (status < 0) {
		fprintf(stderr, "Cannot talk to rtnetlink\n");
		return FALSE;
	}
	return TRUE;
}

static int netlink_talk(struct nlmsghdr *req, size_t replysize,
			struct nlmsghdr *reply)
{
	struct netlink_fd fd;
	int ret = FALSE;

	if (!netlink_open(&fd))
		return FALSE;

	if (reply == NULL)
		req->nlmsg_flags |= NLM_F_ACK;

	if (!netlink_send(&fd, req))
		goto out;

	if (reply != NULL) {
		reply->nlmsg_len = replysize;
		ret = netlink_receive(&fd, reply);
	} else {
		ret = TRUE;
	}
out:
	netlink_close(&fd);
	return ret;
}

int netlink_route_get(struct sockaddr *dst, u_int16_t *mtu, char *ifname)
{
	struct {
		struct nlmsghdr 	n;
		union {
			struct rtmsg		r;
			struct ifinfomsg	i;
		};
		char   			buf[1024];
	} req;
	struct rtmsg *r = NLMSG_DATA(&req.n);
	struct rtattr *rta[RTA_MAX+1];
	struct rtattr *rtax[RTAX_MAX+1];
	struct rtattr *ifla[IFLA_MAX+1];
	int index;

	memset(&req, 0, sizeof(req));
	req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
	req.n.nlmsg_flags = NLM_F_REQUEST;
	req.n.nlmsg_type = RTM_GETROUTE;
	req.r.rtm_family = dst->sa_family;

	netlink_add_rtaddr_l(&req.n, sizeof(req), RTA_DST, dst);
	req.r.rtm_dst_len = 32;

	if (!netlink_talk(&req.n, sizeof(req), &req.n))
		return FALSE;

	netlink_parse_rtattr(rta, RTA_MAX, RTM_RTA(r),
			     RTM_PAYLOAD(&req.n));

	if (mtu != NULL) {
		if (rta[RTA_METRICS] == NULL)
			return FALSE;

		netlink_parse_rtattr(rtax, RTAX_MAX,
				     RTA_DATA(rta[RTA_METRICS]),
				     RTA_PAYLOAD(rta[RTA_METRICS]));
		if (rtax[RTAX_MTU] == NULL)
			return FALSE;

		*mtu = *(int*) RTA_DATA(rtax[RTAX_MTU]);
	}

	if (ifname != NULL) {
		if (rta[RTA_OIF] == NULL)
			return FALSE;

		index = *(int*) RTA_DATA(rta[RTA_OIF]);

		memset(&req, 0, sizeof(req));
		req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
		req.n.nlmsg_flags = NLM_F_REQUEST;
		req.n.nlmsg_type = RTM_GETLINK;
		req.i.ifi_index = index;
		if (!netlink_talk(&req.n, sizeof(req), &req.n))
			return FALSE;

		netlink_parse_rtattr(ifla, IFLA_MAX, IFLA_RTA(r),
				     IFLA_PAYLOAD(&req.n));
		if (ifla[IFLA_IFNAME] == NULL)
			return FALSE;

		memcpy(ifname, RTA_DATA(ifla[IFLA_IFNAME]),
		       RTA_PAYLOAD(ifla[IFLA_IFNAME]));
	}

	return TRUE;
}
void process_nl_new_route (struct nlmsghdr *nlh)
{
    struct rtmsg             *rtm                       = NULL;
    struct rtattr            *rt_attr                   = NULL;
    int                      rt_length                  = 0;
    lispd_iface_elt          *iface                     = NULL;
    int                      iface_index                = 0;
    char                     iface_name[IF_NAMESIZE];
    lisp_addr_t              gateway                    = {.afi=AF_UNSPEC};
    lisp_addr_t              dst                        = {.afi=AF_UNSPEC};;


    rtm = (struct rtmsg *) NLMSG_DATA (nlh);

    if ((rtm->rtm_family != AF_INET) && (rtm->rtm_family != AF_INET6)) {
        lispd_log_msg(LISP_LOG_DEBUG_2,"process_nl_new_route: Unknown adddress family");
        return;
    }

    if (rtm->rtm_table != RT_TABLE_MAIN) {
        /* Not interested in routes/gateways affecting tables other the main routing table */
        return;
    }

    rt_attr = (struct rtattr *)RTM_RTA(rtm);
    rt_length = RTM_PAYLOAD(nlh);

    for (; RTA_OK(rt_attr, rt_length); rt_attr = RTA_NEXT(rt_attr, rt_length)) {
        switch (rt_attr->rta_type) {
        case RTA_OIF:
            iface_index = *(int *)RTA_DATA(rt_attr);
            iface = get_interface_from_index(iface_index);
            if_indextoname(iface_index, iface_name);
            if (iface == NULL) {
                lispd_log_msg(LISP_LOG_DEBUG_2, "process_nl_new_route: the netlink message is not for any interface associated with RLOCs (%s)",
                              iface_name);
                return;
            }
            break;
        case RTA_GATEWAY:
            gateway.afi = rtm->rtm_family;
            switch (gateway.afi) {
            case AF_INET:
                memcpy(&(gateway.address),(struct in_addr *)RTA_DATA(rt_attr), sizeof(struct in_addr));
                break;
            case AF_INET6:
                memcpy(&(gateway.address),(struct in6_addr *)RTA_DATA(rt_attr), sizeof(struct in6_addr));
                break;
            default:
                break;
            }
            break;
        case RTA_DST: // We check if the new route message contains a destintaion. If it is, then the gateway address is not a default route. Discard it
            dst.afi = rtm->rtm_family;
            switch (dst.afi) {
            case AF_INET:
                memcpy(&(dst.address),(struct in_addr *)RTA_DATA(rt_attr), sizeof(struct in_addr));
                break;
            case AF_INET6:
                memcpy(&(dst.address),(struct in6_addr *)RTA_DATA(rt_attr), sizeof(struct in6_addr));
                break;
            default:
                break;
            }
            break;
        default:
            break;
        }
    }
    if (gateway.afi != AF_UNSPEC && iface_index != 0 && dst.afi == AF_UNSPEC) {
        /* Check default afi*/
        if (default_rloc_afi != AF_UNSPEC && default_rloc_afi != gateway.afi) {
            lispd_log_msg(LISP_LOG_DEBUG_1,  "process_nl_new_route: Default RLOC afi defined (-a #): Skipped %s gateway in iface %s",
                          (gateway.afi == AF_INET) ? "IPv4" : "IPv6",iface->iface_name);
            return;
        }

        /* Check if the addres is a global address*/
        if (is_link_local_addr(gateway) == TRUE) {
            lispd_log_msg(LISP_LOG_DEBUG_2,"process_nl_new_route: the extractet address from the netlink "
                          "messages is a local link address: %s discarded", get_char_from_lisp_addr_t(gateway));
            return;
        }

        /* Process the new gateway */
        lispd_log_msg(LISP_LOG_DEBUG_1,  "process_nl_new_route: Process new gateway associated to the interface %s:  %s",
                      iface_name, get_char_from_lisp_addr_t(gateway));
        process_new_gateway(gateway,iface);
    }
}
Beispiel #19
0
static void netlink_neigh(struct ufpd_thread *thread, struct nlmsghdr *nlh)
{
	struct ndmsg *neigh_entry;
	struct rtattr *route_attr;
	struct neigh_table *neigh;
	int route_attr_len;
	int ifindex;
	int family;
	uint8_t dst_addr[16] = {};
	uint8_t dst_mac[ETH_ALEN] = {};
	int i, port_index = -1;

	neigh_entry = (struct ndmsg *)NLMSG_DATA(nlh);
	family		= neigh_entry->ndm_family;
	ifindex		= neigh_entry->ndm_ifindex;
	port_index 	= -1;

	for(i = 0; i < thread->num_ports; i++){
		if(ufp_tun_index(thread->plane, i) == ifindex){
			port_index = i;
			break;
		}
	}

	if(port_index < 0)
		goto out;

	route_attr = (struct rtattr *)RTM_RTA(neigh_entry);
	route_attr_len = RTM_PAYLOAD(nlh);

	while(RTA_OK(route_attr, route_attr_len)){
		switch(route_attr->rta_type){
		case NDA_DST:
			memcpy(dst_addr, RTA_DATA(route_attr),
				RTA_PAYLOAD(route_attr));
			break;
		case NDA_LLADDR:
			memcpy(dst_mac, RTA_DATA(route_attr),
				RTA_PAYLOAD(route_attr));
			break;
		default:
			break;
		}

		route_attr = RTA_NEXT(route_attr, route_attr_len);
	}

	switch(family){
	case AF_INET:
		neigh = thread->neigh_inet[port_index];
		break;
	case AF_INET6:
		neigh = thread->neigh_inet6[port_index];
		break;
	default:
		goto out;
		break;
	}

	switch(nlh->nlmsg_type){
	case RTM_NEWNEIGH:
		neigh_add(neigh, family, dst_addr, dst_mac,
			thread->mpool);
		break;
	case RTM_DELNEIGH:
		neigh_delete(neigh, family, dst_addr);
		break;
	default:
		break;
	}

out:
	return;
}