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))); }
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); }