Esempio n. 1
0
static void print_key(struct rtattr *key)
{
	SPRINT_BUF(keyid);

	print_string(PRINT_ANY, "key", " key %s\n",
		     hexstring_n2a(RTA_DATA(key), RTA_PAYLOAD(key),
				   keyid, sizeof(keyid)));
}
Esempio n. 2
0
int print_linkinfo(const struct sockaddr_nl *who,
		   struct nlmsghdr *n, void *arg)
{
	FILE *fp = (FILE*)arg;
	struct ifinfomsg *ifi = NLMSG_DATA(n);
	struct rtattr * tb[IFLA_MAX+1];
	int len = n->nlmsg_len;
	unsigned m_flag = 0;

	if (n->nlmsg_type != RTM_NEWLINK && n->nlmsg_type != RTM_DELLINK)
		return 0;

	len -= NLMSG_LENGTH(sizeof(*ifi));
	if (len < 0)
		return -1;

	if (filter.ifindex && ifi->ifi_index != filter.ifindex)
		return 0;
	if (filter.up && !(ifi->ifi_flags&IFF_UP))
		return 0;

	parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len);
	if (tb[IFLA_IFNAME] == NULL) {
		fprintf(stderr, "BUG: device with ifindex %d has nil ifname\n", ifi->ifi_index);
	}
	if (filter.label &&
	    (!filter.family || filter.family == AF_PACKET) &&
	    fnmatch(filter.label, RTA_DATA(tb[IFLA_IFNAME]), 0))
		return 0;

	if (tb[IFLA_GROUP]) {
		int group = *(int*)RTA_DATA(tb[IFLA_GROUP]);
		if (filter.group != -1 && group != filter.group)
			return -1;
	}

	if (tb[IFLA_MASTER]) {
		int master = *(int*)RTA_DATA(tb[IFLA_MASTER]);
		if (filter.master > 0 && master != filter.master)
			return -1;
	}
	else if (filter.master > 0)
		return -1;

	if (filter.kind) {
		if (tb[IFLA_LINKINFO]) {
			char *kind = parse_link_kind(tb[IFLA_LINKINFO]);

			if (strcmp(kind, filter.kind))
				return -1;
		} else {
			return -1;
		}
	}

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

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

	if (tb[IFLA_LINK]) {
		SPRINT_BUF(b1);
		int iflink = *(int*)RTA_DATA(tb[IFLA_LINK]);
		if (iflink == 0)
			fprintf(fp, "@NONE: ");
		else {
			if (tb[IFLA_LINK_NETNSID])
				fprintf(fp, "@if%d: ", iflink);
			else {
				fprintf(fp, "@%s: ", ll_idx_n2a(iflink, b1));
				m_flag = ll_index_to_flags(iflink);
				m_flag = !(m_flag & IFF_UP);
			}
		}
	} else {
		fprintf(fp, ": ");
	}
	print_link_flags(fp, ifi->ifi_flags, m_flag);

	if (tb[IFLA_MTU])
		fprintf(fp, "mtu %u ", *(int*)RTA_DATA(tb[IFLA_MTU]));
	if (tb[IFLA_QDISC])
		fprintf(fp, "qdisc %s ", rta_getattr_str(tb[IFLA_QDISC]));
	if (tb[IFLA_MASTER]) {
		SPRINT_BUF(b1);
		fprintf(fp, "master %s ", ll_idx_n2a(*(int*)RTA_DATA(tb[IFLA_MASTER]), b1));
	}

	if (tb[IFLA_PHYS_PORT_ID]) {
		SPRINT_BUF(b1);
		fprintf(fp, "portid %s ",
			hexstring_n2a(RTA_DATA(tb[IFLA_PHYS_PORT_ID]),
				      RTA_PAYLOAD(tb[IFLA_PHYS_PORT_ID]),
				      b1, sizeof(b1)));
	}

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

	if (do_link && tb[IFLA_LINKMODE])
		print_linkmode(fp, tb[IFLA_LINKMODE]);

	if (tb[IFLA_GROUP]) {
		SPRINT_BUF(b1);
		int group = *(int*)RTA_DATA(tb[IFLA_GROUP]);
		fprintf(fp, "group %s ", rtnl_group_n2a(group, b1, sizeof(b1)));
	}

	if (filter.showqueue)
		print_queuelen(fp, tb);

	if (!filter.family || filter.family == AF_PACKET || show_details) {
		SPRINT_BUF(b1);
		fprintf(fp, "%s", _SL_);
		fprintf(fp, "    link/%s ", ll_type_n2a(ifi->ifi_type, b1, sizeof(b1)));

		if (tb[IFLA_ADDRESS]) {
			color_fprintf(fp, COLOR_MAC, "%s",
					ll_addr_n2a(RTA_DATA(tb[IFLA_ADDRESS]),
						RTA_PAYLOAD(tb[IFLA_ADDRESS]),
						ifi->ifi_type,
						b1, sizeof(b1)));
		}
		if (tb[IFLA_BROADCAST]) {
			if (ifi->ifi_flags&IFF_POINTOPOINT)
				fprintf(fp, " peer ");
			else
				fprintf(fp, " brd ");
			fprintf(fp, "%s", ll_addr_n2a(RTA_DATA(tb[IFLA_BROADCAST]),
						      RTA_PAYLOAD(tb[IFLA_BROADCAST]),
						      ifi->ifi_type,
						      b1, sizeof(b1)));
		}
	}

	if (tb[IFLA_LINK_NETNSID]) {
		int id = *(int*)RTA_DATA(tb[IFLA_LINK_NETNSID]);

		if (id >= 0)
			fprintf(fp, " link-netnsid %d", id);
		else
			fprintf(fp, " link-netnsid unknown");
	}

	if (tb[IFLA_PROMISCUITY] && show_details)
		fprintf(fp, " promiscuity %u ",
			*(int*)RTA_DATA(tb[IFLA_PROMISCUITY]));

	if (tb[IFLA_LINKINFO] && show_details)
		print_linktype(fp, tb[IFLA_LINKINFO]);

	if (do_link && tb[IFLA_AF_SPEC] && show_details)
		print_af_spec(fp, tb[IFLA_AF_SPEC]);

	if ((do_link || show_details) && tb[IFLA_IFALIAS]) {
		fprintf(fp, "%s    alias %s", _SL_,
			rta_getattr_str(tb[IFLA_IFALIAS]));
	}

	if (do_link && show_stats) {
		fprintf(fp, "%s", _SL_);
		__print_link_stats(fp, tb);
	}

	if ((do_link || show_details) && tb[IFLA_VFINFO_LIST] && tb[IFLA_NUM_VF]) {
		struct rtattr *i, *vflist = tb[IFLA_VFINFO_LIST];
		int rem = RTA_PAYLOAD(vflist);
		for (i = RTA_DATA(vflist); RTA_OK(i, rem); i = RTA_NEXT(i, rem))
			print_vfinfo(fp, i);
	}

	fprintf(fp, "\n");
	fflush(fp);
	return 1;
}
int main(int argc, char **argv)
{
	int opt;
	int do_list = 0;
	char *do_load = NULL;

	while ((opt = getopt(argc, argv, "h?b:lf:a:n:kR:B:")) != EOF) {
		switch (opt) {
	        case 'b':
			dbname = optarg;
			break;
		case 'f':
			if (do_load) {
				fprintf(stderr, "Duplicate option -f\n");
				usage();
			}
			do_load = optarg;
			break;
		case 'l':
			do_list = 1;
			break;
		case 'a':
			active_probing = atoi(optarg);
			break;
		case 'n':
			negative_timeout = atoi(optarg);
			break;
		case 'k':
			no_kernel_broadcasts = 1;
			break;
		case 'R':
			if ((broadcast_rate = atoi(optarg)) <= 0 ||
			    (broadcast_rate = 1000/broadcast_rate) <= 0) {
				fprintf(stderr, "Invalid ARP rate\n");
				exit(-1);
			}
			break;
		case 'B':
			if ((broadcast_burst = atoi(optarg)) <= 0 ||
			    (broadcast_burst = 1000*broadcast_burst) <= 0) {
				fprintf(stderr, "Invalid ARP burst\n");
				exit(-1);
			}
			break;
		case 'h':
		case '?':
		default:
			usage();
		}
	}
	argc -= optind;
	argv += optind;

	if (argc > 0) {
		ifnum = argc;
		ifnames = argv;
		ifvec = malloc(argc*sizeof(int));
		if (!ifvec) {
			perror("malloc");
			exit(-1);
		}
	}

	if ((udp_sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
		perror("socket");
		exit(-1);
	}

        if (ifnum) {
		int i;
		struct ifreq ifr;
		memset(&ifr, 0, sizeof(ifr));
		for (i=0; i<ifnum; i++) {
			strncpy(ifr.ifr_name, ifnames[i], IFNAMSIZ);
			if (ioctl(udp_sock, SIOCGIFINDEX, &ifr)) {
				perror("ioctl(SIOCGIFINDEX)");
				exit(-1);;
			}
			ifvec[i] = ifr.ifr_ifindex;
		}
	}

	dbase = dbopen(dbname, O_CREAT|O_RDWR, 0644, DB_HASH, NULL);
	if (dbase == NULL) {
		perror("db_open");
		exit(-1);
	}

	if (do_load) {
		char buf[128];
		FILE *fp;
		struct dbkey k;
		DBT dbkey, dbdat;

		dbkey.data = &k;
		dbkey.size = sizeof(k);

		if (strcmp(do_load, "-") == 0 || strcmp(do_load, "--") == 0) {
			fp = stdin;
		} else if ((fp = fopen(do_load, "r")) == NULL) {
			perror("fopen");
			goto do_abort;
		}

		buf[sizeof(buf)-1] = 0;
		while (fgets(buf, sizeof(buf)-1, fp)) {
			__u8 b1[6];
			char ipbuf[128];
			char macbuf[128];

			if (buf[0] == '#')
				continue;

			if (sscanf(buf, "%u%s%s", &k.iface, ipbuf, macbuf) != 3) {
				fprintf(stderr, "Wrong format of input file \"%s\"\n", do_load);
				goto do_abort;
			}
			if (strncmp(macbuf, "FAILED:", 7) == 0)
				continue;
			if (!inet_aton(ipbuf, (struct in_addr*)&k.addr)) {
				fprintf(stderr, "Invalid IP address: \"%s\"\n", ipbuf);
				goto do_abort;
			}

			dbdat.data = hexstring_a2n(macbuf, b1, 6);
			if (dbdat.data == NULL)
				goto do_abort;
			dbdat.size = 6;

			if (dbase->put(dbase, &dbkey, &dbdat, 0)) {
				perror("hash->put");
				goto do_abort;
			}
		}
		dbase->sync(dbase, 0);
		if (fp != stdin)
			fclose(fp);
	}

	if (do_list) {
		DBT dbkey, dbdat;
		printf("%-8s %-15s %s\n", "#Ifindex", "IP", "MAC");
		while (dbase->seq(dbase, &dbkey, &dbdat, R_NEXT) == 0) {
			struct dbkey *key = dbkey.data;
			if (handle_if(key->iface)) {
				if (!IS_NEG(dbdat.data)) {
					char b1[18];
					printf("%-8d %-15s %s\n",
					       key->iface,
					       inet_ntoa(*(struct in_addr*)&key->addr),
					       hexstring_n2a(dbdat.data, 6, b1, 18));
				} else {
					printf("%-8d %-15s FAILED: %dsec ago\n",
					       key->iface,
					       inet_ntoa(*(struct in_addr*)&key->addr),
					       NEG_AGE(dbdat.data));
				}
			}
		}
	}

	if (do_load || do_list)
		goto out;

	pset[0].fd = socket(PF_PACKET, SOCK_DGRAM, 0);
	if (pset[0].fd < 0) {
		perror("socket");
		exit(-1);
	}

	if (1) {
		struct sockaddr_ll sll;
		memset(&sll, 0, sizeof(sll));
		sll.sll_family = AF_PACKET;
		sll.sll_protocol = htons(ETH_P_ARP);
		sll.sll_ifindex = (ifnum == 1 ? ifvec[0] : 0);
		if (bind(pset[0].fd, (struct sockaddr*)&sll, sizeof(sll)) < 0) {
			perror("bind");
			goto do_abort;
		}
	}

	if (rtnl_open(&rth, RTMGRP_NEIGH) < 0) {
		perror("rtnl_open");
		goto do_abort;
	}
	pset[1].fd = rth.fd;

	load_initial_table();

	if (daemon(0, 0)) {
		perror("arpd: daemon");
		goto do_abort;
	}

	openlog("arpd", LOG_PID | LOG_CONS, LOG_DAEMON);
	catch_signal(SIGINT, sig_exit);
	catch_signal(SIGTERM, sig_exit);
	catch_signal(SIGHUP, sig_sync);
	catch_signal(SIGUSR1, sig_stats);

#define EVENTS (POLLIN|POLLPRI|POLLERR|POLLHUP)
	pset[0].events = EVENTS;
	pset[0].revents = 0;
	pset[1].events = EVENTS;
	pset[1].revents = 0;

	sigsetjmp(env, 1);

	for (;;) {
		in_poll = 1;

		if (do_exit)
			break;
		if (do_sync) {
			in_poll = 0;
			dbase->sync(dbase, 0);
			do_sync = 0;
			in_poll = 1;
		}
		if (do_stats)
			send_stats();
		if (poll(pset, 2, 30000) > 0) {
			in_poll = 0;
			if (pset[0].revents&EVENTS)
				get_arp_pkt();
			if (pset[1].revents&EVENTS)
				get_kern_msg();
		} else {
			do_sync = 1;
		}
	}

	undo_sysctl_adjustments();
out:
	dbase->close(dbase);
	exit(0);

do_abort:
	dbase->close(dbase);
	exit(-1);
}