Beispiel #1
0
static int
netl_handler(struct netl_handle *h,
			 pktj_unused(struct sockaddr_nl *nladdr),
			 struct nlmsghdr *hdr, void *args)
{
	int len = hdr->nlmsg_len;

	switch (hdr->nlmsg_type) {
		// TODO RTM_SETLINK
	case RTM_NEWLINK:
	case RTM_DELLINK:
		{
			struct ifinfomsg *ifi = NLMSG_DATA(hdr);
			struct rtattr *rta_tb[IFLA_MAX + 1];
			struct ether_addr lladdr;
			int ifid = ifi->ifi_index;
			int mtu = -1;
			const char *ifname = "";
			uint16_t vlanid = 0;
			oper_state_t state = LINK_UNKNOWN;
			link_action_t action = LINK_ADD;

			len -= NLMSG_LENGTH(sizeof(*ifi));

			if (len < 0) {
				// incomplete message
				return -1;
			}

			parse_rtattr_flags(rta_tb, IFLA_MAX, IFLA_RTA(ifi), len, 0);

			if (ifi->ifi_type != ARPHRD_ETHER)
				return 0;		// This is not ethernet
			if (rta_tb[IFLA_IFNAME] == NULL)
				return -1;		// There should be a name, this is a bug

			if (hdr->nlmsg_type == RTM_DELLINK)
				action = LINK_DELETE;

			if (rta_tb[IFLA_MTU])
				mtu = *(int *) RTA_DATA(rta_tb[IFLA_MTU]);
			if (rta_tb[IFLA_IFNAME])
				ifname = rta_getattr_str(rta_tb[IFLA_IFNAME]);
			if (rta_tb[IFLA_OPERSTATE])
				state = rta_getattr_u8(rta_tb[IFLA_OPERSTATE]);
			if (rta_tb[IFLA_ADDRESS])
				memcpy(&lladdr.addr_bytes, RTA_DATA(rta_tb[IFLA_ADDRESS]),
					   sizeof(lladdr.addr_bytes));

			if (rta_tb[IFLA_LINKINFO]) {
				struct rtattr *linkinfo[IFLA_INFO_MAX + 1];
				parse_rtattr_nested(linkinfo, IFLA_INFO_MAX,
									rta_tb[IFLA_LINKINFO]);
				if (linkinfo[IFLA_INFO_KIND]) {
					char *kind = RTA_DATA(linkinfo[IFLA_INFO_KIND]);
					//XXX only handle vlan type for now
					if (!strcmp(kind, "vlan")) {
						vlanid = get_vlan_id(linkinfo);
					} else {
						//TODO receive an IF without vlan id
					}
				}

			}

			if (h->cb.link != NULL) {
				h->cb.link(action, ifid, &lladdr, mtu,
						   ifname, state, vlanid, args);
			}

		}
		break;
	}


	if (hdr->nlmsg_type == RTM_NEWADDR || hdr->nlmsg_type == RTM_DELADDR) {
		//struct if_rtattrs attrs;
		struct rtattr *rta_tb[IFA_MAX + 1];
		struct ifaddrmsg *ifa = NLMSG_DATA(hdr);
		//unsigned int ifa_flags;
		unsigned char buf_addr[sizeof(struct in6_addr)];
		addr_action_t action;
		len -= NLMSG_LENGTH(sizeof(*ifa));

		if (len < 0) {
			// incomplete message
			return -1;
		}

		if (hdr->nlmsg_type == RTM_NEWADDR)
			action = ADDR_ADD;
		else if (hdr->nlmsg_type == RTM_DELADDR)
			action = ADDR_DELETE;
		else
			return -1;


		parse_rtattr_flags(rta_tb, IFA_MAX, IFA_RTA(ifa), len, 0);
		//ifa_flags = get_ifa_flags(ifa, rta_tb[IFA_FLAGS]);

		if (!rta_tb[IFA_LOCAL])
			rta_tb[IFA_LOCAL] = rta_tb[IFA_ADDRESS];
		if (!rta_tb[IFA_ADDRESS])
			rta_tb[IFA_ADDRESS] = rta_tb[IFA_LOCAL];

		if (rta_tb[IFA_LOCAL]) {
			//we may optimize by passing directly RTA_DATA(rta_tb[IFA_LOCAL]) to the cb
			memcpy(buf_addr, RTA_DATA(rta_tb[IFA_LOCAL]),
				   RTA_PAYLOAD(rta_tb[IFA_LOCAL]));
		}
		switch (ifa->ifa_family) {
		case AF_INET:
			if (h->cb.addr4 != NULL) {
				h->cb.addr4(action, ifa->ifa_index,
							(struct in_addr *) buf_addr,
							ifa->ifa_prefixlen, args);
			}
			break;
		case AF_INET6:
			if (h->cb.addr6 != NULL) {
				h->cb.addr6(action, ifa->ifa_index,
							(struct in6_addr *) buf_addr,
							ifa->ifa_prefixlen, args);
			}
			break;
		default:
			//only handling IP
			return -1;
		}
	}

	if (hdr->nlmsg_type == RTM_NEWROUTE || hdr->nlmsg_type == RTM_DELROUTE) {
		struct rtattr *tb[RTA_MAX + 1];
		struct rtmsg *r = NLMSG_DATA(hdr);
		//__u32 table;
		len -= NLMSG_LENGTH(sizeof(*r));

		if (len < 0) {
			// incomplete message
			return -1;
		}

		if (r->rtm_family != RTNL_FAMILY_IPMR &&
			r->rtm_family != RTNL_FAMILY_IP6MR) {
			// This is an unicast route, no interest for multicast
			route_action_t action;
			if (hdr->nlmsg_type == RTM_NEWROUTE)
				action = ROUTE_ADD;
			else
				action = ROUTE_DELETE;

			parse_rtattr_flags(tb, RTA_MAX, RTM_RTA(r), len, 0);
			//table = rtm_get_table(r, tb);

			switch(r->rtm_type) {
				case RTN_UNICAST:
					if (!tb[RTA_DST])
						return 0;

					if (!tb[RTA_GATEWAY])
						return 0;
				case RTN_BLACKHOLE:
					break;
				default:
					return 0;
			}

			switch (r->rtm_family) {
			case AF_INET:
				if (h->cb.route4 != NULL) {
					h->cb.route4(r, action, RTA_DATA(tb[RTA_DST]),
								 r->rtm_dst_len, RTA_DATA(tb[RTA_GATEWAY]),
								 r->rtm_type, args);
				}
				break;
			case AF_INET6:
				if (h->cb.route6 != NULL) {
					h->cb.route6(r, action, RTA_DATA(tb[RTA_DST]),
								 r->rtm_dst_len, RTA_DATA(tb[RTA_GATEWAY]),
								 r->rtm_type, args);
				}
				break;
			default:
				//only handling IP
				return 0;
			}
		}
	}

	if (hdr->nlmsg_type == RTM_NEWNEIGH || hdr->nlmsg_type == RTM_DELNEIGH) {
		struct ndmsg *neighbor = NLMSG_DATA(hdr);
		struct rtattr *tb[NDA_MAX + 1];
		uint16_t vlanid = 0;

		len -= NLMSG_LENGTH(sizeof(*neighbor));

		if (len < 0) {
			// incomplete message
			return -1;
		}
		// Ignore non-ip
		if (neighbor->ndm_family != AF_INET &&
			neighbor->ndm_family != AF_INET6)
			return 0;

		parse_rtattr_flags(tb, NDA_MAX, RTM_RTA(neighbor), len, 0);

		neighbor_action_t action;
		if (hdr->nlmsg_type == RTM_NEWNEIGH)
			action = NEIGHBOR_ADD;
		else
			action = NEIGHBOR_DELETE;
		if (tb[NDA_VLAN])
			vlanid = rta_getattr_u16(tb[NDA_VLAN]);
		switch (neighbor->ndm_family) {
		case AF_INET:
			if (h->cb.neighbor4 != NULL) {
				if (tb[NDA_LLADDR]) {
					h->cb.neighbor4(action, neighbor->ndm_ifindex,
									RTA_DATA(tb[NDA_DST]),
									RTA_DATA(tb[NDA_LLADDR]),
									neighbor->ndm_state, vlanid, args);
				} else {
					h->cb.neighbor4(action, neighbor->ndm_ifindex,
									RTA_DATA(tb[NDA_DST]),
									&invalid_mac,
									neighbor->ndm_state, vlanid, args);
				}
			}
			break;
		case AF_INET6:
			if (h->cb.neighbor6 != NULL) {
				if (tb[NDA_LLADDR]) {
					h->cb.neighbor6(action, neighbor->ndm_ifindex,
									RTA_DATA(tb[NDA_DST]),
									RTA_DATA(tb[NDA_LLADDR]),
									neighbor->ndm_state, vlanid, args);
				} else {
					h->cb.neighbor6(action, neighbor->ndm_ifindex,
									RTA_DATA(tb[NDA_DST]),
									&invalid_mac,
									neighbor->ndm_state, vlanid, args);
				}
			}
			break;
		default:
			//only handling IP
			return 0;
		}
	}

	return 0;
}
Beispiel #2
0
int print_linkinfo(const struct sockaddr_nl *who,
                   struct nlmsghdr *n, void *arg)
{
    FILE *fp = arg;
    int len = n->nlmsg_len;
    struct ifinfomsg *ifi = NLMSG_DATA(n);
    struct rtattr * tb[IFLA_MAX+1];
    char b1[IFNAMSIZ];

    len -= NLMSG_LENGTH(sizeof(*ifi));
    if (len < 0) {
        fprintf(stderr, "Message too short!\n");
        return -1;
    }

    if (!(ifi->ifi_family == AF_BRIDGE || ifi->ifi_family == AF_UNSPEC))
        return 0;

    if (filter_index && filter_index != ifi->ifi_index)
        return 0;

    parse_rtattr_flags(tb, IFLA_MAX, IFLA_RTA(ifi), len, NLA_F_NESTED);

    if (tb[IFLA_IFNAME] == NULL) {
        fprintf(stderr, "BUG: nil ifname\n");
        return -1;
    }

    if (n->nlmsg_type == RTM_DELLINK)
        fprintf(fp, "Deleted ");

    fprintf(fp, "%d: %s ", ifi->ifi_index,
            tb[IFLA_IFNAME] ? rta_getattr_str(tb[IFLA_IFNAME]) : "<nil>");

    if (tb[IFLA_OPERSTATE])
        print_operstate(fp, rta_getattr_u8(tb[IFLA_OPERSTATE]));

    if (tb[IFLA_LINK]) {
        SPRINT_BUF(b1);
        int iflink = rta_getattr_u32(tb[IFLA_LINK]);
        if (iflink == 0)
            fprintf(fp, "@NONE: ");
        else
            fprintf(fp, "@%s: ",
                    if_indextoname(iflink, b1));
    } else
        fprintf(fp, ": ");

    print_link_flags(fp, ifi->ifi_flags);

    if (tb[IFLA_MTU])
        fprintf(fp, "mtu %u ", rta_getattr_u32(tb[IFLA_MTU]));

    if (tb[IFLA_MASTER])
        fprintf(fp, "master %s ",
                if_indextoname(rta_getattr_u32(tb[IFLA_MASTER]), b1));

    if (tb[IFLA_PROTINFO]) {
        if (tb[IFLA_PROTINFO]->rta_type & NLA_F_NESTED) {
            struct rtattr *prtb[IFLA_BRPORT_MAX+1];

            parse_rtattr_nested(prtb, IFLA_BRPORT_MAX,
                                tb[IFLA_PROTINFO]);

            if (prtb[IFLA_BRPORT_STATE])
                print_portstate(fp,
                                rta_getattr_u8(prtb[IFLA_BRPORT_STATE]));
            if (prtb[IFLA_BRPORT_PRIORITY])
                fprintf(fp, "priority %hu ",
                        rta_getattr_u16(prtb[IFLA_BRPORT_PRIORITY]));
            if (prtb[IFLA_BRPORT_COST])
                fprintf(fp, "cost %u ",
                        rta_getattr_u32(prtb[IFLA_BRPORT_COST]));

            if (show_details) {
                fprintf(fp, "%s    ", _SL_);

                if (prtb[IFLA_BRPORT_MODE])
                    print_onoff(fp, "hairpin",
                                rta_getattr_u8(prtb[IFLA_BRPORT_MODE]));
                if (prtb[IFLA_BRPORT_GUARD])
                    print_onoff(fp, "guard",
                                rta_getattr_u8(prtb[IFLA_BRPORT_GUARD]));
                if (prtb[IFLA_BRPORT_PROTECT])
                    print_onoff(fp, "root_block",
                                rta_getattr_u8(prtb[IFLA_BRPORT_PROTECT]));
                if (prtb[IFLA_BRPORT_FAST_LEAVE])
                    print_onoff(fp, "fastleave",
                                rta_getattr_u8(prtb[IFLA_BRPORT_FAST_LEAVE]));
                if (prtb[IFLA_BRPORT_LEARNING])
                    print_onoff(fp, "learning",
                                rta_getattr_u8(prtb[IFLA_BRPORT_LEARNING]));
                if (prtb[IFLA_BRPORT_LEARNING_SYNC])
                    print_onoff(fp, "learning_sync",
                                rta_getattr_u8(prtb[IFLA_BRPORT_LEARNING_SYNC]));
                if (prtb[IFLA_BRPORT_UNICAST_FLOOD])
                    print_onoff(fp, "flood",
                                rta_getattr_u8(prtb[IFLA_BRPORT_UNICAST_FLOOD]));
            }
        } else
            print_portstate(fp, rta_getattr_u8(tb[IFLA_PROTINFO]));
    }

    if (tb[IFLA_AF_SPEC]) {
        /* This is reported by HW devices that have some bridging
         * capabilities.
         */
        struct rtattr *aftb[IFLA_BRIDGE_MAX+1];

        parse_rtattr_nested(aftb, IFLA_BRIDGE_MAX, tb[IFLA_AF_SPEC]);

        if (aftb[IFLA_BRIDGE_MODE])
            print_hwmode(fp, rta_getattr_u16(aftb[IFLA_BRIDGE_MODE]));
    }

    fprintf(fp, "\n");
    fflush(fp);
    return 0;
}