static void dissect_igmp_v2(struct pkt_buff *pkt) { char addr[INET_ADDRSTRLEN]; uint16_t csum; struct igmp_v2_msg *msg = (struct igmp_v2_msg *) pkt_pull(pkt, sizeof(*msg)); if (msg == NULL) return; switch (msg->type) { case RGMP_HELLO: case RGMP_BYE: case RGMP_JOIN_GROUP: case RGMP_LEAVE_GROUP: tprintf(" [ IGMPv2 (RGMP)"); break; default: tprintf(" [ IGMPv2"); break; } PRINT_FRIENDLY_NAMED_MSG_TYPE(msg->type); tprintf(", Max Resp Time (%u)", msg->max_resp_time); csum = calc_csum(msg, sizeof(*msg) + pkt_len(pkt), 0); tprintf(", CSum (0x%.4x) is %s", ntohs(msg->checksum), csum ? colorize_start_full(black, red) "bogus (!)" colorize_end() : "ok"); if (csum) tprintf(" - %s should be %x%s", colorize_start_full(black, red), csum_expected(msg->checksum, csum), colorize_end()); inet_ntop(AF_INET, &msg->group_address, addr, sizeof(addr)); tprintf(", Group Addr (%s)", addr); tprintf(" ]\n"); }
static void nlmsg_print(uint16_t family, struct nlmsghdr *hdr) { u16 nlmsg_flags = hdr->nlmsg_flags; char type[32]; char flags[128]; char procname[PATH_MAX]; /* Look up the process name if message is not coming from the kernel. * * Note that the port id is not necessarily equal to the PID of the * receiving process (e.g. if the application is multithreaded or using * multiple sockets). In these cases we're not able to find a matching * PID and the information will not be printed. */ if (hdr->nlmsg_pid != 0) { if (proc_get_cmdline(hdr->nlmsg_pid, procname, sizeof(procname)) < 0) snprintf(procname, sizeof(procname), "unknown process"); } else snprintf(procname, sizeof(procname), "kernel"); tprintf(" [ NLMSG "); tprintf("Family %d (%s%s%s), ", family, colorize_start(bold), nlmsg_family2str(family), colorize_end()); tprintf("Len %u, ", hdr->nlmsg_len); tprintf("Type 0x%.4x (%s%s%s), ", hdr->nlmsg_type, colorize_start(bold), nlmsg_type2str(family, hdr->nlmsg_type, type, sizeof(type)), colorize_end()); tprintf("Flags 0x%.4x (%s%s%s), ", nlmsg_flags, colorize_start(bold), nlmsg_flags ? nl_nlmsg_flags2str(nlmsg_flags, flags, sizeof(flags)) : "none", colorize_end()); tprintf("Seq-Nr %u, ", hdr->nlmsg_seq); tprintf("PID %u", hdr->nlmsg_pid); if (procname[0]) tprintf(" (%s%s%s)", colorize_start(bold), basename(procname), colorize_end()); tprintf(" ]\n"); switch (family) { case NETLINK_ROUTE: rtnl_msg_print(hdr); break; case NETLINK_GENERIC: genl_msg_print(hdr); break; default: nlmsg_print_raw(hdr); } }
static void dissect_igmp_v3_membership_query(struct pkt_buff *pkt) { char addr[INET_ADDRSTRLEN]; size_t n; uint16_t csum; uint32_t *src_addr; struct igmp_v3_membership_query *msg = (struct igmp_v3_membership_query *) pkt_pull(pkt, sizeof(*msg)); if (msg == NULL) return; tprintf(" [ IGMPv3"); PRINT_FRIENDLY_NAMED_MSG_TYPE(msg->type); tprintf(", Max Resp Code (0x%.2x => %u)", msg->max_resp_code, DECODE_MAX_RESP_CODE(msg->max_resp_code)); csum = calc_csum(msg, sizeof(*msg) + pkt_len(pkt), 0); tprintf(", CSum (0x%.4x) is %s", ntohs(msg->checksum), csum ? colorize_start_full(black, red) "bogus (!)" colorize_end() : "ok"); if (csum) tprintf(" - %s should be %x%s", colorize_start_full(black, red), csum_expected(msg->checksum, csum), colorize_end()); inet_ntop(AF_INET, &msg->group_address, addr, sizeof(addr)); /* S Flag (Suppress Router-Side Processing) */ tprintf(", Suppress (%u)", msg->s_flag ? 1 : 0); /* QRV (Querier's Robustness Variable) */ tprintf(", QRV (%u)", msg->qrv); /* QQIC (Querier's Query Interval Code) */ tprintf(", QQIC (0x%.2x => %u)", msg->qqic, DECODE_QQIC(msg->qqic)); tprintf(", Group Addr (%s)", addr); n = ntohs(msg->number_of_sources); tprintf(", Num Src (%zu)", n); if (n--) { src_addr = (uint32_t *) pkt_pull(pkt, sizeof(*src_addr)); if (src_addr != NULL) { inet_ntop(AF_INET, src_addr, addr, sizeof(addr)); tprintf(", Src Addr (%s", addr); while (n--) { src_addr = (uint32_t *) pkt_pull(pkt, sizeof(*src_addr)); if (src_addr == NULL) break; inet_ntop(AF_INET, src_addr, addr, sizeof(addr)); tprintf(", %s", addr); } tprintf(")"); } } tprintf(" ]\n"); }
static void tcp(struct pkt_buff *pkt) { struct tcphdr *tcp = (struct tcphdr *) pkt_pull(pkt, sizeof(*tcp)); uint16_t src, dest; char *src_name, *dest_name; if (tcp == NULL) return; src = ntohs(tcp->source); dest = ntohs(tcp->dest); src_name = lookup_port_tcp(src); dest_name = lookup_port_tcp(dest); tprintf(" [ TCP "); tprintf("Port (%u", src); if (src_name) tprintf(" (%s%s%s)", colorize_start(bold), src_name, colorize_end()); tprintf(" => %u", dest); if (dest_name) tprintf(" (%s%s%s)", colorize_start(bold), dest_name, colorize_end()); tprintf("), "); tprintf("SN (0x%x), ", ntohl(tcp->seq)); tprintf("AN (0x%x), ", ntohl(tcp->ack_seq)); tprintf("DataOff (%u), ", tcp->doff); tprintf("Res (%u), ", tcp->res1); tprintf("Flags ("); if (tcp->fin) tprintf("FIN "); if (tcp->syn) tprintf("SYN "); if (tcp->rst) tprintf("RST "); if (tcp->psh) tprintf("PSH "); if (tcp->ack) tprintf("ACK "); if (tcp->urg) tprintf("URG "); if (tcp->ece) tprintf("ECE "); if (tcp->cwr) tprintf("CWR "); tprintf("), "); tprintf("Window (%u), ", ntohs(tcp->window)); tprintf("CSum (0x%.4x), ", ntohs(tcp->check)); tprintf("UrgPtr (%u)", ntohs(tcp->urg_ptr)); tprintf(" ]\n"); }
static void auth_hdr(struct pkt_buff *pkt) { ssize_t hdr_len; struct auth_hdr *auth_ops; auth_ops = (struct auth_hdr *) pkt_pull(pkt, sizeof(*auth_ops)); if (auth_ops == NULL) return; hdr_len = (auth_ops->h_payload_len * 4) + 8; tprintf(" [ Authentication Header "); tprintf("NextHdr (%u), ", auth_ops->h_next_header); if (hdr_len > pkt_len(pkt) || hdr_len < 0){ tprintf("HdrLen (%u, %zd Bytes %s), ", auth_ops->h_payload_len, hdr_len, colorize_start_full(black, red) "invalid" colorize_end()); return; } tprintf("HdrLen (%u, %zd Bytes), ",auth_ops->h_payload_len, hdr_len); tprintf("Reserved (0x%x), ", ntohs(auth_ops->h_reserved)); /* TODO * Upgrade for Extended (64-bit) Sequence Number * http://tools.ietf.org/html/rfc4302#section-2.5.1 */ tprintf("SPI (0x%x), ", ntohl(auth_ops->h_spi)); tprintf("SNF (0x%x), ", ntohl(auth_ops->h_snf)); tprintf("ICV 0x"); for (size_t i = sizeof(struct auth_hdr); i < hdr_len; i++) tprintf("%02x", *pkt_pull(pkt, 1)); tprintf(" ]\n"); pkt_set_proto(pkt, ð_lay3, auth_ops->h_next_header); }
static void hop_by_hop(struct pkt_buff *pkt) { uint16_t hdr_ext_len; ssize_t opt_len; struct hop_by_hophdr *hop_ops; hop_ops = (struct hop_by_hophdr *) pkt_pull(pkt, sizeof(*hop_ops)); if (hop_ops == NULL) return; /* Total Header Length in Bytes */ hdr_ext_len = (hop_ops->hdr_len + 1) * 8; /* Options length in Bytes */ opt_len = hdr_ext_len - sizeof(*hop_ops); tprintf("\t [ Hop-by-Hop Options "); tprintf("NextHdr (%u), ", hop_ops->h_next_header); if (opt_len > pkt_len(pkt) || opt_len < 0){ tprintf("HdrExtLen (%u, %u Bytes, %s)", hop_ops->hdr_len, hdr_ext_len, colorize_start_full(black, red) "invalid" colorize_end()); return; } tprintf("HdrExtLen (%u, %u Bytes)", hop_ops->hdr_len, hdr_ext_len); dissect_opt_hop(pkt, &opt_len); tprintf(" ]\n"); pkt_pull(pkt, opt_len); pkt_set_proto(pkt, ð_lay3, hop_ops->h_next_header); }
static void nlmsg_less(struct pkt_buff *pkt) { struct nlmsghdr *hdr = (struct nlmsghdr *) pkt_pull(pkt, NLMSG_HDRLEN); uint16_t family = ntohs(pkt->sll->sll_protocol); char type[32]; if (hdr == NULL) return; tprintf(" NLMSG Family %d (%s%s%s), ", family, colorize_start(bold), nlmsg_family2str(family), colorize_end()); tprintf("Type %u (%s%s%s)", hdr->nlmsg_type, colorize_start(bold), nlmsg_type2str(family, hdr->nlmsg_type, type, sizeof(type)), colorize_end()); }
static void tcp_less(struct pkt_buff *pkt) { struct tcphdr *tcp = (struct tcphdr *) pkt_pull(pkt, sizeof(*tcp)); uint16_t src, dest; char *src_name, *dest_name; if (tcp == NULL) return; src = ntohs(tcp->source); dest = ntohs(tcp->dest); src_name = lookup_port_tcp(src); dest_name = lookup_port_tcp(dest); tprintf(" TCP %u", src); if(src_name) tprintf("(%s%s%s)", colorize_start(bold), src_name, colorize_end()); tprintf("/%u", dest); if(dest_name) tprintf("(%s%s%s)", colorize_start(bold), dest_name, colorize_end()); tprintf(" F%s",colorize_start(bold)); if (tcp->fin) tprintf(" FIN"); if (tcp->syn) tprintf(" SYN"); if (tcp->rst) tprintf(" RST"); if (tcp->psh) tprintf(" PSH"); if (tcp->ack) tprintf(" ACK"); if (tcp->urg) tprintf(" URG"); if (tcp->ece) tprintf(" ECE"); if (tcp->cwr) tprintf(" CWR"); tprintf("%s Win %u S/A 0x%x/0x%x", colorize_end(), ntohs(tcp->window), ntohl(tcp->seq), ntohl(tcp->ack_seq)); }
static void dissect_igmp_v1(struct pkt_buff *pkt) { char addr[INET_ADDRSTRLEN]; uint16_t csum; struct igmp_v1_msg *msg = (struct igmp_v1_msg *) pkt_pull(pkt, sizeof(*msg)); if (msg == NULL) return; tprintf(" [ IGMPv1"); PRINT_FRIENDLY_NAMED_MSG_TYPE(msg->version__type); csum = calc_csum(msg, sizeof(*msg) + pkt_len(pkt), 0); tprintf(", CSum (0x%.4x) is %s", ntohs(msg->checksum), csum ? colorize_start_full(black, red) "bogus (!)" colorize_end() : "ok"); if (csum) tprintf(" - %s should be %x%s", colorize_start_full(black, red), csum_expected(msg->checksum, csum), colorize_end()); inet_ntop(AF_INET, &msg->group_address, addr, sizeof(addr)); tprintf(", Group Addr (%s)", addr); tprintf(" ]\n"); }
static void udp(struct pkt_buff *pkt) { struct udphdr *udp = (struct udphdr *) pkt_pull(pkt, sizeof(*udp)); ssize_t len; uint16_t src, dest; char *src_name, *dest_name; if (udp == NULL) return; len = ntohs(udp->len) - sizeof(*udp); src = ntohs(udp->source); dest = ntohs(udp->dest); src_name = lookup_port_udp(src); dest_name = lookup_port_udp(dest); tprintf(" [ UDP "); tprintf("Port (%u", src); if (src_name) tprintf(" (%s%s%s)", colorize_start(bold), src_name, colorize_end()); tprintf(" => %u", dest); if (dest_name) tprintf(" (%s%s%s)", colorize_start(bold), dest_name, colorize_end()); tprintf("), "); if(len > pkt_len(pkt) || len < 0){ tprintf("Len (%u) %s, ", ntohs(udp->len), colorize_start_full(black, red) "invalid" colorize_end()); } tprintf("Len (%u Bytes, %zd Bytes Data), ", ntohs(udp->len), len); tprintf("CSum (0x%.4x)", ntohs(udp->check)); tprintf(" ]\n"); }
static void udp_less(struct pkt_buff *pkt) { struct udphdr *udp = (struct udphdr *) pkt_pull(pkt, sizeof(*udp)); uint16_t src, dest; char *src_name, *dest_name; if (udp == NULL) return; src = ntohs(udp->source); dest = ntohs(udp->dest); src_name = lookup_port_udp(src); dest_name = lookup_port_udp(dest); tprintf(" UDP %u", src); if(src_name) tprintf("(%s%s%s)", colorize_start(bold), src_name, colorize_end()); tprintf("/%u", dest); if (dest_name) tprintf("(%s%s%s)", colorize_start(bold), dest_name, colorize_end()); }
static void routing(struct pkt_buff *pkt) { uint16_t hdr_ext_len; ssize_t data_len; struct routinghdr *routing; routing = (struct routinghdr *) pkt_pull(pkt, sizeof(*routing)); if (routing == NULL) return; /* Total Header Length in Bytes */ hdr_ext_len = (routing->h_hdr_ext_len + 1) * 8; /* Data length in Bytes */ data_len = hdr_ext_len - sizeof(*routing); tprintf("\t [ Routing "); tprintf("NextHdr (%u), ", routing->h_next_header); if (data_len > pkt_len(pkt) || data_len < 0){ tprintf("HdrExtLen (%u, %u Bytes %s), ", routing->h_hdr_ext_len, hdr_ext_len, colorize_start_full(black, red) "invalid" colorize_end()); return; } tprintf("HdrExtLen (%u, %u Bytes), ", routing->h_hdr_ext_len, hdr_ext_len); tprintf("Type (%u), ", routing->h_routing_type); tprintf("Left (%u), ", routing->h_segments_left); switch (routing->h_routing_type) { case ROUTING_HEADER_TYPE_0: dissect_routinghdr_type_0_norm(pkt, &data_len); break; default: tprintf("Type %u is unknown", routing->h_routing_type); } tprintf(" ]\n"); if (data_len > pkt_len(pkt) || data_len < 0) return; pkt_pull(pkt, data_len); pkt_set_proto(pkt, ð_lay3, routing->h_next_header); }
static void genl_msg_print(struct nlmsghdr *hdr) { struct genlmsghdr *genl; if (hdr->nlmsg_type != GENL_ID_CTRL) { nlmsg_print_raw(hdr); return; } genl = NLMSG_DATA(hdr); tprintf(" [ Cmd %u (%s%s%s)", genl->cmd, colorize_start(bold), genl_cmd2str(genl->cmd), colorize_end()); tprintf(", Version %u", genl->version); tprintf(", Reserved %u", genl->reserved); tprintf(" ]\n"); genl_print_ctrl(hdr); }
static void ethernet_less(struct pkt_buff *pkt) { uint8_t *src_mac, *dst_mac; struct ethhdr *eth = (struct ethhdr *) pkt_pull(pkt, sizeof(*eth)); if (eth == NULL) return; src_mac = eth->h_source; dst_mac = eth->h_dest; tprintf(" %s => %s ", lookup_vendor((src_mac[0] << 16) | (src_mac[1] << 8) | src_mac[2]), lookup_vendor((dst_mac[0] << 16) | (dst_mac[1] << 8) | dst_mac[2])); tprintf("%s%s%s", colorize_start(bold), lookup_ether_type(ntohs(eth->h_proto)), colorize_end()); pkt_set_proto(pkt, ð_lay2, ntohs(eth->h_proto)); }
static void mobility(struct pkt_buff *pkt) { uint16_t hdr_ext_len; ssize_t message_data_len; struct mobilityhdr *mobility; mobility = (struct mobilityhdr *) pkt_pull(pkt, sizeof(*mobility)); if (mobility == NULL) return; /* Total Header Length in Bytes */ hdr_ext_len = (mobility->hdr_len + 1) * 8; /* Total Message Data length in Bytes*/ message_data_len = (hdr_ext_len - sizeof(*mobility)); tprintf("\t [ Mobility "); tprintf("NextHdr (%u), ", mobility->payload_proto); if (message_data_len > pkt_len(pkt) || message_data_len < 0){ tprintf("HdrExtLen (%u, %u Bytes %s), ", mobility->hdr_len, hdr_ext_len, colorize_start_full(black, red) "invalid" colorize_end()); return; } tprintf("HdrExtLen (%u, %u Bytes), ", mobility->hdr_len, hdr_ext_len); tprintf("MH Type (%u), ", mobility->MH_type); tprintf("Res (0x%x), ", mobility->reserved); tprintf("Chks (0x%x), ", ntohs(mobility->chksum)); tprintf("MH Data "); get_mh_type(pkt, &message_data_len, &mobility->MH_type); tprintf(" ]\n"); if (message_data_len > pkt_len(pkt) || message_data_len < 0) return; pkt_pull(pkt, message_data_len); pkt_set_proto(pkt, ð_lay3, mobility->payload_proto); }
static void ethernet(struct pkt_buff *pkt) { char *type; uint8_t *src_mac, *dst_mac; struct ethhdr *eth = (struct ethhdr *) pkt_pull(pkt, sizeof(*eth)); if (eth == NULL) return; src_mac = eth->h_source; dst_mac = eth->h_dest; tprintf(" [ Eth "); tprintf("MAC (%.2x:%.2x:%.2x:%.2x:%.2x:%.2x => ", src_mac[0], src_mac[1], src_mac[2], src_mac[3], src_mac[4], src_mac[5]); tprintf("%.2x:%.2x:%.2x:%.2x:%.2x:%.2x), ", dst_mac[0], dst_mac[1], dst_mac[2], dst_mac[3], dst_mac[4], dst_mac[5]); tprintf("Proto (0x%.4x", ntohs(eth->h_proto)); type = lookup_ether_type(ntohs(eth->h_proto)); if (type) tprintf(", %s%s%s", colorize_start(bold), type, colorize_end()); tprintf(") ]\n"); tprintf(" [ Vendor "); tprintf("(%s => %s)", lookup_vendor((src_mac[0] << 16) | (src_mac[1] << 8) | src_mac[2]), lookup_vendor((dst_mac[0] << 16) | (dst_mac[1] << 8) | dst_mac[2])); tprintf(" ]\n"); pkt_set_proto(pkt, ð_lay2, ntohs(eth->h_proto)); }
static void header(void) { printf("%s%s%s\n", colorize_start(bold), PROGNAME_STRING " " VERSION_STRING, colorize_end()); }
static void xmit_slowpath_or_die(struct ctx *ctx, unsigned int cpu, unsigned long orig_num) { int ret, icmp_sock = -1; unsigned long num = 1, i = 0; struct timeval start, end, diff; unsigned long long tx_bytes = 0, tx_packets = 0; struct packet_dyn *pktd; struct sockaddr_ll saddr = { .sll_family = PF_PACKET, .sll_halen = ETH_ALEN, .sll_ifindex = device_ifindex(ctx->device), }; if (ctx->num > 0) num = ctx->num; if (ctx->num == 0 && orig_num > 0) num = 0; if (ctx->smoke_test) icmp_sock = xmit_smoke_setup(ctx); drop_privileges(ctx->enforce, ctx->uid, ctx->gid); bug_on(gettimeofday(&start, NULL)); while (likely(sigint == 0 && num > 0 && plen > 0)) { pktd = &packet_dyn[i]; if (pktd->clen + pktd->rlen + pktd->slen) { apply_counter(i); apply_randomizer(i); apply_csum16(i); } retry: ret = sendto(sock, packets[i].payload, packets[i].len, 0, (struct sockaddr *) &saddr, sizeof(saddr)); if (unlikely(ret < 0)) { if (errno == ENOBUFS) { sched_yield(); goto retry; } if (ctx->smoke_test) panic("Sendto error: %s!\n", strerror(errno)); } tx_bytes += packets[i].len; tx_packets++; if (ctx->smoke_test) { ret = xmit_smoke_probe(icmp_sock, ctx); if (unlikely(ret < 0)) { printf("%sSmoke test alert:%s\n", colorize_start(bold), colorize_end()); printf(" Remote host seems to be unresponsive to ICMP probes!\n"); printf(" Last instance was packet%lu, seed:%u, trafgen snippet:\n\n", i, seed); dump_trafgen_snippet(packets[i].payload, packets[i].len); break; } } if (!ctx->rand) { i++; if (i >= plen) i = 0; } else i = rand() % plen; if (ctx->num > 0) num--; if ((ctx->gap.tv_sec | ctx->gap.tv_nsec) > 0) nanosleep(&ctx->gap, NULL); } bug_on(gettimeofday(&end, NULL)); timersub(&end, &start, &diff); if (ctx->smoke_test) close(icmp_sock); stats[cpu].tx_packets = tx_packets; stats[cpu].tx_bytes = tx_bytes; stats[cpu].tv_sec = diff.tv_sec; stats[cpu].tv_usec = diff.tv_usec; stats[cpu].state |= CPU_STATS_STATE_RES; } static void xmit_fastpath_or_die(struct ctx *ctx, unsigned int cpu, unsigned long orig_num) { int ifindex = device_ifindex(ctx->device); uint8_t *out = NULL; unsigned int it = 0; unsigned long num = 1, i = 0; size_t size = ring_size(ctx->device, ctx->reserve_size); struct ring tx_ring; struct frame_map *hdr; struct timeval start, end, diff; struct packet_dyn *pktd; unsigned long long tx_bytes = 0, tx_packets = 0; set_sock_prio(sock, 512); ring_tx_setup(&tx_ring, sock, size, ifindex, ctx->jumbo_support, ctx->verbose); drop_privileges(ctx->enforce, ctx->uid, ctx->gid); if (ctx->num > 0) num = ctx->num; if (ctx->num == 0 && orig_num > 0) num = 0; bug_on(gettimeofday(&start, NULL)); while (likely(sigint == 0 && num > 0 && plen > 0)) { if (!user_may_pull_from_tx(tx_ring.frames[it].iov_base)) { int ret = pull_and_flush_tx_ring(sock); if (unlikely(ret < 0)) { /* We could hit EBADF if the socket has been closed before * the timer was triggered. */ if (errno != EBADF && errno != ENOBUFS) panic("Flushing TX_RING failed: %s!\n", strerror(errno)); } continue; } hdr = tx_ring.frames[it].iov_base; out = ((uint8_t *) hdr) + TPACKET2_HDRLEN - sizeof(struct sockaddr_ll); hdr->tp_h.tp_snaplen = packets[i].len; hdr->tp_h.tp_len = packets[i].len; pktd = &packet_dyn[i]; if (pktd->clen + pktd->rlen + pktd->slen) { apply_counter(i); apply_randomizer(i); apply_csum16(i); } fmemcpy(out, packets[i].payload, packets[i].len); tx_bytes += packets[i].len; tx_packets++; if (!ctx->rand) { i++; if (i >= plen) i = 0; } else i = rand() % plen; kernel_may_pull_from_tx(&hdr->tp_h); it++; if (it >= tx_ring.layout.tp_frame_nr) it = 0; if (ctx->num > 0) num--; } bug_on(gettimeofday(&end, NULL)); timersub(&end, &start, &diff); pull_and_flush_tx_ring_wait(sock); destroy_tx_ring(sock, &tx_ring); stats[cpu].tx_packets = tx_packets; stats[cpu].tx_bytes = tx_bytes; stats[cpu].tv_sec = diff.tv_sec; stats[cpu].tv_usec = diff.tv_usec; stats[cpu].state |= CPU_STATS_STATE_RES; }
static void ipv4(struct pkt_buff *pkt) { uint16_t csum, frag_off, h_tot_len; char src_ip[INET_ADDRSTRLEN]; char dst_ip[INET_ADDRSTRLEN]; struct ipv4hdr *ip = (struct ipv4hdr *) pkt_pull(pkt, sizeof(*ip)); uint8_t *opt, *trailer; unsigned int trailer_len = 0; ssize_t opts_len, opt_len; struct sockaddr_in sas, sad; const char *city, *region, *country; if (!ip) return; frag_off = ntohs(ip->h_frag_off); h_tot_len = ntohs(ip->h_tot_len); csum = calc_csum(ip, ip->h_ihl * 4, 0); inet_ntop(AF_INET, &ip->h_saddr, src_ip, sizeof(src_ip)); inet_ntop(AF_INET, &ip->h_daddr, dst_ip, sizeof(dst_ip)); if ((pkt_len(pkt) + sizeof(*ip)) > h_tot_len) { trailer_len = pkt_len(pkt) + sizeof(*ip) - h_tot_len; trailer = pkt->data + h_tot_len + trailer_len; } if (trailer_len) { tprintf(" [ Eth trailer "); while (trailer_len--) { tprintf("%x", *(trailer - trailer_len)); } tprintf(" ]\n"); } tprintf(" [ IPv4 "); tprintf("Addr (%s => %s), ", src_ip, dst_ip); tprintf("Proto (%u), ", ip->h_protocol); tprintf("TTL (%u), ", ip->h_ttl); tprintf("TOS (%u), ", ip->h_tos); tprintf("Ver (%u), ", ip->h_version); tprintf("IHL (%u), ", ip->h_ihl); tprintf("Tlen (%u), ", ntohs(ip->h_tot_len)); tprintf("ID (%u), ", ntohs(ip->h_id)); tprintf("Res (%u), NoFrag (%u), MoreFrag (%u), FragOff (%u), ", FRAG_OFF_RESERVED_FLAG(frag_off) ? 1 : 0, FRAG_OFF_NO_FRAGMENT_FLAG(frag_off) ? 1 : 0, FRAG_OFF_MORE_FRAGMENT_FLAG(frag_off) ? 1 : 0, FRAG_OFF_FRAGMENT_OFFSET(frag_off)); tprintf("CSum (0x%.4x) is %s", ntohs(ip->h_check), csum ? colorize_start_full(black, red) "bogus (!)" colorize_end() : "ok"); if (csum) tprintf("%s should be 0x%.4x%s", colorize_start_full(black, red), csum_expected(ip->h_check, csum), colorize_end()); tprintf(" ]\n"); memset(&sas, 0, sizeof(sas)); sas.sin_family = PF_INET; sas.sin_addr.s_addr = ip->h_saddr; memset(&sad, 0, sizeof(sad)); sad.sin_family = PF_INET; sad.sin_addr.s_addr = ip->h_daddr; if (geoip_working()) { tprintf("\t[ Geo ("); if ((country = geoip4_country_name(sas))) { tprintf("%s", country); if ((region = geoip4_region_name(sas))) tprintf(" / %s", region); if ((city = geoip4_city_name(sas))) tprintf(" / %s", city); } else { tprintf("local"); } tprintf(" => "); if ((country = geoip4_country_name(sad))) { tprintf("%s", country); if ((region = geoip4_region_name(sad))) tprintf(" / %s", region); if ((city = geoip4_city_name(sad))) tprintf(" / %s", city); } else { tprintf("local"); } tprintf(") ]\n"); } opts_len = max((uint8_t) ip->h_ihl, sizeof(*ip) / sizeof(uint32_t)) * sizeof(uint32_t) - sizeof(*ip); for (opt = pkt_pull(pkt, opts_len); opt && opts_len > 0; opt++) { tprintf(" [ Option Copied (%u), Class (%u), Number (%u)", IP_OPT_COPIED_FLAG(*opt) ? 1 : 0, IP_OPT_CLASS(*opt), IP_OPT_NUMBER(*opt)); switch (*opt) { case IP_OPT_EOOL: case IP_OPT_NOP: tprintf(" ]\n"); opts_len--; break; default: /* * Assuming that EOOL and NOP are the only single-byte * options, treat all other options as variable in * length with a minimum of 2. * * TODO: option length might be incorrect in malformed packets, * check and handle that */ opt_len = *(++opt); if (opt_len > opts_len) { tprintf(", Len (%zd, invalid) ]\n", opt_len); goto out; } else tprintf(", Len (%zd) ]\n", opt_len); opts_len -= opt_len; tprintf(" [ Data hex "); for (opt_len -= 2; opt_len > 0; opt_len--) tprintf(" %.2x", *(++opt)); tprintf(" ]\n"); break; } } out: /* cut off everything that is not part of IPv4 payload */ /* XXX there could still be an Ethernet trailer included or others */ pkt_trim(pkt, pkt_len(pkt) - min(pkt_len(pkt), (ntohs(ip->h_tot_len) - ip->h_ihl * sizeof(uint32_t)))); pkt_set_proto(pkt, ð_lay3, ip->h_protocol); }
static void dissect_igmp_v3_membership_report(struct pkt_buff *pkt) { char addr[INET_ADDRSTRLEN]; size_t m, n; uint16_t csum; uint32_t *src_addr; struct igmp_v3_group_record *rec; struct igmp_v3_membership_report *msg = (struct igmp_v3_membership_report *) pkt_pull(pkt, sizeof(*msg)); if (msg == NULL) return; tprintf(" [ IGMPv3"); PRINT_FRIENDLY_NAMED_MSG_TYPE(msg->type); csum = calc_csum(msg, sizeof(*msg) + pkt_len(pkt), 0); tprintf(", CSum (0x%.4x) is %s", ntohs(msg->checksum), csum ? colorize_start_full(black, red) "bogus (!)" colorize_end() : "ok"); if (csum) tprintf(" - %s should be %x%s", colorize_start_full(black, red), csum_expected(msg->checksum, csum), colorize_end()); m = ntohs(msg->number_of_group_records); tprintf(", Num Group Rec (%zu)", m); tprintf(" ]\n"); while (m--) { rec = (struct igmp_v3_group_record *) pkt_pull(pkt, sizeof(*rec)); if (rec == NULL) break; tprintf(" [ Group Record"); if (friendly_group_rec_type_name(rec->record_type)) tprintf(" Type (%u, %s)", rec->record_type, friendly_group_rec_type_name(rec->record_type)); else tprintf(" Type (%u)", rec->record_type); n = ntohs(rec->number_of_sources); tprintf(", Num Src (%zu)", n); inet_ntop(AF_INET, &rec->multicast_address, addr, sizeof(addr)); tprintf(", Multicast Addr (%s)", addr); if (n--) { src_addr = (uint32_t *) pkt_pull(pkt, sizeof(*src_addr)); if (src_addr != NULL) { inet_ntop(AF_INET, src_addr, addr, sizeof(addr)); tprintf(", Src Addr (%s", addr); while (n--) { src_addr = (uint32_t *) pkt_pull(pkt, sizeof(*src_addr)); if (src_addr == NULL) break; inet_ntop(AF_INET, src_addr, addr, sizeof(addr)); tprintf(", %s", addr); } tprintf(")"); } } tprintf(" ]\n"); } tprintf("\n"); }
static void header(void) { printf("%s%s%s\n", colorize_start(bold), "curvetun " VERSION_STRING, colorize_end()); }
static void xmit_slowpath_or_die(struct ctx *ctx, int cpu, unsigned long orig_num) { int ret, icmp_sock = -1; unsigned long num = 1, i = 0; struct timeval start, end, diff; unsigned long long tx_bytes = 0, tx_packets = 0; struct packet_dyn *pktd; struct sockaddr_ll saddr = { .sll_family = PF_PACKET, .sll_halen = ETH_ALEN, .sll_ifindex = device_ifindex(ctx->device), }; if (ctx->num > 0) num = ctx->num; if (ctx->num == 0 && orig_num > 0) num = 0; if (ctx->smoke_test) icmp_sock = xmit_smoke_setup(ctx); drop_privileges(ctx->enforce, ctx->uid, ctx->gid); bug_on(gettimeofday(&start, NULL)); while (likely(sigint == 0) && likely(num > 0) && likely(plen > 0)) { pktd = &packet_dyn[i]; if (pktd->clen + pktd->rlen + pktd->slen) { apply_counter(i); apply_randomizer(i); apply_csum16(i); } retry: ret = sendto(sock, packets[i].payload, packets[i].len, 0, (struct sockaddr *) &saddr, sizeof(saddr)); if (unlikely(ret < 0)) { if (errno == ENOBUFS) { sched_yield(); goto retry; } panic("Sendto error: %s!\n", strerror(errno)); } tx_bytes += packets[i].len; tx_packets++; if (ctx->smoke_test) { ret = xmit_smoke_probe(icmp_sock, ctx); if (unlikely(ret < 0)) { printf("%sSmoke test alert:%s\n", colorize_start(bold), colorize_end()); printf(" Remote host seems to be unresponsive to ICMP probes!\n"); printf(" Last instance was packet%lu, seed:%u, trafgen snippet:\n\n", i, seed); dump_trafgen_snippet(packets[i].payload, packets[i].len); break; } } if (!ctx->rand) { i++; if (i >= plen) i = 0; } else i = rand() % plen; if (ctx->num > 0) num--; if (ctx->gap > 0) usleep(ctx->gap); } bug_on(gettimeofday(&end, NULL)); timersub(&end, &start, &diff); if (ctx->smoke_test) close(icmp_sock); stats[cpu].tx_packets = tx_packets; stats[cpu].tx_bytes = tx_bytes; stats[cpu].tv_sec = diff.tv_sec; stats[cpu].tv_usec = diff.tv_usec; stats[cpu].state |= CPU_STATS_STATE_RES; } static void xmit_fastpath_or_die(struct ctx *ctx, int cpu, unsigned long orig_num) { int ifindex = device_ifindex(ctx->device); uint8_t *out = NULL; unsigned int it = 0; unsigned long num = 1, i = 0, size; struct ring tx_ring; struct frame_map *hdr; struct timeval start, end, diff; struct packet_dyn *pktd; unsigned long long tx_bytes = 0, tx_packets = 0; fmemset(&tx_ring, 0, sizeof(tx_ring)); size = ring_size(ctx->device, ctx->reserve_size); set_sock_prio(sock, 512); set_packet_loss_discard(sock); setup_tx_ring_layout(sock, &tx_ring, size, ctx->jumbo_support); create_tx_ring(sock, &tx_ring, ctx->verbose); mmap_tx_ring(sock, &tx_ring); alloc_tx_ring_frames(sock, &tx_ring); bind_tx_ring(sock, &tx_ring, ifindex); drop_privileges(ctx->enforce, ctx->uid, ctx->gid); if (ctx->kpull) interval = ctx->kpull; if (ctx->num > 0) num = ctx->num; if (ctx->num == 0 && orig_num > 0) num = 0; set_itimer_interval_value(&itimer, 0, interval); setitimer(ITIMER_REAL, &itimer, NULL); bug_on(gettimeofday(&start, NULL)); while (likely(sigint == 0) && likely(num > 0) && likely(plen > 0)) { while (user_may_pull_from_tx(tx_ring.frames[it].iov_base) && likely(num > 0)) { hdr = tx_ring.frames[it].iov_base; out = ((uint8_t *) hdr) + TPACKET2_HDRLEN - sizeof(struct sockaddr_ll); hdr->tp_h.tp_snaplen = packets[i].len; hdr->tp_h.tp_len = packets[i].len; pktd = &packet_dyn[i]; if (pktd->clen + pktd->rlen + pktd->slen) { apply_counter(i); apply_randomizer(i); apply_csum16(i); } fmemcpy(out, packets[i].payload, packets[i].len); tx_bytes += packets[i].len; tx_packets++; if (!ctx->rand) { i++; if (i >= plen) i = 0; } else i = rand() % plen; kernel_may_pull_from_tx(&hdr->tp_h); it++; if (it >= tx_ring.layout.tp_frame_nr) it = 0; if (ctx->num > 0) num--; if (unlikely(sigint == 1)) break; } } bug_on(gettimeofday(&end, NULL)); timersub(&end, &start, &diff); timer_purge(); destroy_tx_ring(sock, &tx_ring); stats[cpu].tx_packets = tx_packets; stats[cpu].tx_bytes = tx_bytes; stats[cpu].tv_sec = diff.tv_sec; stats[cpu].tv_usec = diff.tv_usec; stats[cpu].state |= CPU_STATS_STATE_RES; }
static void rtnl_print_ifinfo(struct nlmsghdr *hdr) { struct ifinfomsg *ifi = NLMSG_DATA(hdr); struct rtattr *attr = IFLA_RTA(ifi); uint32_t attrs_len = IFLA_PAYLOAD(hdr); char flags[256]; char if_addr[64] = {}; char *af_link = "unknown"; if (hdr->nlmsg_len < NLMSG_LENGTH(sizeof(*ifi))) return; if (ifi->ifi_family == AF_UNSPEC) af_link = "unspec"; else if (ifi->ifi_family == AF_BRIDGE) af_link = "bridge"; tprintf(" [ Link Family %d (%s%s%s)", ifi->ifi_family, colorize_start(bold), af_link, colorize_end()); tprintf(", Type %d (%s%s%s)", ifi->ifi_type, colorize_start(bold), device_type2str(ifi->ifi_type), colorize_end()); tprintf(", Index %d", ifi->ifi_index); tprintf(", Flags 0x%x (%s%s%s)", ifi->ifi_flags, colorize_start(bold), rtnl_link_flags2str(ifi->ifi_flags, flags, sizeof(flags)), colorize_end()); tprintf(", Change 0x%x (%s%s%s) ]\n", ifi->ifi_change, colorize_start(bold), rtnl_link_flags2str(ifi->ifi_change, flags, sizeof(flags)), colorize_end()); for (; RTA_OK(attr, attrs_len); attr = RTA_NEXT(attr, attrs_len)) { switch (attr->rta_type) { case IFLA_ADDRESS: rta_fmt(attr, "Address %s", device_addr2str(RTA_DATA(attr), RTA_LEN(attr), ifi->ifi_type, if_addr, sizeof(if_addr))); break; case IFLA_BROADCAST: rta_fmt(attr, "Broadcast %s", device_addr2str(RTA_DATA(attr), RTA_LEN(attr), ifi->ifi_type, if_addr, sizeof(if_addr))); break; case IFLA_IFNAME: rta_fmt(attr, "Name %s%s%s", colorize_start(bold), RTA_STR(attr), colorize_end()); break; case IFLA_MTU: rta_fmt(attr, "MTU %d", RTA_INT(attr)); break; case IFLA_LINK: rta_fmt(attr, "Link %d", RTA_INT(attr)); break; case IFLA_QDISC: rta_fmt(attr, "QDisc %s", RTA_STR(attr)); break; case IFLA_OPERSTATE: { uint8_t st = RTA_UINT8(attr); char states[256]; rta_fmt(attr, "Operation state 0x%x (%s%s%s)", st, colorize_start(bold), rtnl_link_operstate2str(st, states, sizeof(states)), colorize_end()); } break; case IFLA_LINKMODE: { uint8_t mode = RTA_UINT8(attr); char str[32]; rta_fmt(attr, "Mode 0x%x (%s%s%s)", mode, colorize_start(bold), rtnl_link_mode2str(mode, str, sizeof(str)), colorize_end()); } break; case IFLA_GROUP: rta_fmt(attr, "Group %d", RTA_INT(attr)); break; case IFLA_TXQLEN: rta_fmt(attr, "Tx queue len %d", RTA_INT(attr)); break; case IFLA_NET_NS_PID: rta_fmt(attr, "Network namespace pid %d", RTA_INT(attr)); break; case IFLA_NET_NS_FD: rta_fmt(attr, "Network namespace fd %d", RTA_INT(attr)); break; default: rta_fmt(attr, "0x%x", attr->rta_type); break; } } }
static void dissect_igmp_v0(struct pkt_buff *pkt) { char addr[INET_ADDRSTRLEN]; uint16_t csum; static const char *reply_codes[] = { "Request Granted", "Request Denied, No Resources", "Request Denied, Invalid Code", "Request Denied, Invalid Group Address", "Request Denied, Invalid Access Key" }; struct igmp_v0_msg *msg = (struct igmp_v0_msg *) pkt_pull(pkt, sizeof(*msg)); if (msg == NULL) return; tprintf(" [ IGMPv0"); PRINT_FRIENDLY_NAMED_MSG_TYPE(msg->type); switch (msg->type) { case IGMP_V0_CREATE_GROUP_REQUEST: switch (msg->code) { case 0: tprintf(", Code (%u, %s)", msg->code, "Public"); break; case 1: tprintf(", Code (%u, %s)", msg->code, "Private"); break; default: tprintf(", Code (%u)", msg->code); } break; case IGMP_V0_CREATE_GROUP_REPLY: case IGMP_V0_JOIN_GROUP_REPLY: case IGMP_V0_LEAVE_GROUP_REPLY: case IGMP_V0_CONFIRM_GROUP_REPLY: if (msg->code < 5) tprintf(", Code (%u, %s)", msg->code, reply_codes[msg->code]); else tprintf(", Code (%u, Request Pending, Retry In %u Seconds)", msg->code, msg->code); break; default: tprintf(", Code (%u)", msg->code); } csum = calc_csum(msg, sizeof(*msg) + pkt_len(pkt), 0); tprintf(", CSum (0x%.4x) is %s", ntohs(msg->checksum), csum ? colorize_start_full(black, red) "bogus (!)" colorize_end() : "ok"); if (csum) tprintf(" - %s should be %x%s", colorize_start_full(black, red), csum_expected(msg->checksum, csum), colorize_end()); tprintf(", Id (%u)", ntohs(msg->identifier)); inet_ntop(AF_INET, &msg->group_address, addr, sizeof(addr)); tprintf(", Group Addr (%s)", addr); tprintf(", Access Key (0x%.16lx)", msg->access_key); tprintf(" ]\n"); }
static void rtnl_print_ifaddr(struct nlmsghdr *hdr) { struct ifaddrmsg *ifa = NLMSG_DATA(hdr); uint32_t attrs_len = IFA_PAYLOAD(hdr); struct rtattr *attr = IFA_RTA(ifa); struct ifa_cacheinfo *ci; char addr_str[256]; char flags[256]; if (hdr->nlmsg_len < NLMSG_LENGTH(sizeof(*ifa))) return; tprintf(" [ Address Family %d (%s%s%s)", ifa->ifa_family, colorize_start(bold), addr_family2str(ifa->ifa_family), colorize_end()); tprintf(", Prefix Len %d", ifa->ifa_prefixlen); tprintf(", Flags %d (%s%s%s)", ifa->ifa_flags, colorize_start(bold), rtnl_addr_flags2str(ifa->ifa_flags, flags, sizeof(flags)), colorize_end()); tprintf(", Scope %d (%s%s%s)", ifa->ifa_scope, colorize_start(bold), scope2str(ifa->ifa_scope), colorize_end()); tprintf(", Link Index %d ]\n", ifa->ifa_index); for (; RTA_OK(attr, attrs_len); attr = RTA_NEXT(attr, attrs_len)) { switch (attr->rta_type) { case IFA_LOCAL: rta_fmt(attr, "Local %s", addr2str(ifa->ifa_family, RTA_DATA(attr), addr_str, sizeof(addr_str))); break; case IFA_ADDRESS: rta_fmt(attr, "Address %s", addr2str(ifa->ifa_family, RTA_DATA(attr), addr_str, sizeof(addr_str))); break; case IFA_BROADCAST: rta_fmt(attr, "Broadcast %s", addr2str(ifa->ifa_family, RTA_DATA(attr), addr_str, sizeof(addr_str))); break; case IFA_MULTICAST: rta_fmt(attr, "Multicast %s", addr2str(ifa->ifa_family, RTA_DATA(attr), addr_str, sizeof(addr_str))); break; case IFA_ANYCAST: rta_fmt(attr, "Anycast %s", addr2str(ifa->ifa_family, RTA_DATA(attr), addr_str, sizeof(addr_str))); break; #ifdef IFA_FLAGS case IFA_FLAGS: rta_fmt(attr, "Flags %d (%s%s%s)", RTA_INT(attr), colorize_start(bold), rtnl_addr_flags2str(RTA_INT(attr), flags, sizeof(flags)), colorize_end()); break; #endif case IFA_LABEL: rta_fmt(attr, "Label %s", RTA_STR(attr)); break; case IFA_CACHEINFO: ci = RTA_DATA(attr); tprintf("\tA: Cache ("); if (ci->ifa_valid == INFINITY) tprintf("valid lft(forever)"); else tprintf("valid lft(%us)", ci->ifa_valid); if (ci->ifa_prefered == INFINITY) tprintf(", prefrd lft(forever)"); else tprintf(", prefrd lft(%us)", ci->ifa_prefered); tprintf(", created on(%.2fs)", (double)ci->cstamp / 100); tprintf(", updated on(%.2fs))", (double)ci->cstamp / 100); tprintf(", Len %d\n", RTA_LEN(attr)); break; default: rta_fmt(attr, "0x%x", attr->rta_type); break; } } }
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]; if (hdr->nlmsg_len < NLMSG_LENGTH(sizeof(*rtm))) return; 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: rta_fmt(attr, "Dst %s", addr2str(rtm->rtm_family, RTA_DATA(attr), addr_str, sizeof(addr_str))); break; case RTA_SRC: rta_fmt(attr, "Src %s", addr2str(rtm->rtm_family, RTA_DATA(attr), addr_str, sizeof(addr_str))); break; case RTA_IIF: rta_fmt(attr, "Iif %d", RTA_INT(attr)); break; case RTA_OIF: rta_fmt(attr, "Oif %d", RTA_INT(attr)); break; case RTA_GATEWAY: rta_fmt(attr, "Gateway %s", addr2str(rtm->rtm_family, RTA_DATA(attr), addr_str, sizeof(addr_str))); break; case RTA_PRIORITY: rta_fmt(attr, "Priority %u", RTA_UINT32(attr)); break; case RTA_PREFSRC: rta_fmt(attr, "Pref Src %s", addr2str(rtm->rtm_family, RTA_DATA(attr), addr_str, sizeof(addr_str))); break; case RTA_MARK: rta_fmt(attr, "Mark 0x%x", RTA_UINT(attr)); break; case RTA_FLOW: rta_fmt(attr, "Flow 0x%x", RTA_UINT(attr)); break; case RTA_TABLE: rta_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 %d\n", RTA_LEN(attr)); break; default: rta_fmt(attr, "0x%x", attr->rta_type); break; } } }
static void rtnl_print_neigh(struct nlmsghdr *hdr) { struct ndmsg *ndm = NLMSG_DATA(hdr); uint32_t attrs_len = NDA_PAYLOAD(hdr); struct rtattr *attr = NDA_RTA(ndm); struct nda_cacheinfo *ci; int hz = get_user_hz(); char addr_str[256]; char hw_addr[30]; char states[256]; char flags[256]; if (hdr->nlmsg_len < NLMSG_LENGTH(sizeof(*ndm))) return; tprintf(" [ Neigh Family %d (%s%s%s)", ndm->ndm_family, colorize_start(bold), addr_family2str(ndm->ndm_family), colorize_end()); tprintf(", Link Index %d", ndm->ndm_ifindex); tprintf(", State %d (%s%s%s)", ndm->ndm_state, colorize_start(bold), flags2str(neigh_states, ndm->ndm_state, states, sizeof(states)), colorize_end()); tprintf(", Flags %d (%s%s%s)", ndm->ndm_flags, colorize_start(bold), flags2str(neigh_flags, ndm->ndm_flags, flags, sizeof(flags)), colorize_end()); tprintf(", Type %d (%s%s%s)", ndm->ndm_type, colorize_start(bold), route_type2str(ndm->ndm_type), colorize_end()); tprintf(" ]\n"); for (; RTA_OK(attr, attrs_len); attr = RTA_NEXT(attr, attrs_len)) { switch (attr->rta_type) { case NDA_DST: rta_fmt(attr, "Address %s", addr2str(ndm->ndm_family, RTA_DATA(attr), addr_str, sizeof(addr_str))); break; case NDA_LLADDR: rta_fmt(attr, "HW Address %s", device_addr2str(RTA_DATA(attr), RTA_LEN(attr), 0, hw_addr, sizeof(hw_addr))); break; case NDA_PROBES: rta_fmt(attr, "Probes %d", RTA_UINT32(attr)); break; case NDA_CACHEINFO: ci = RTA_DATA(attr); tprintf("\tA: Cache ("); tprintf("confirmed(%ds)", ci->ndm_confirmed / hz); tprintf(", used(%ds)", ci->ndm_used / hz); tprintf(", updated(%ds)", ci->ndm_updated / hz); tprintf(", refcnt(%d))", ci->ndm_refcnt); tprintf(", Len %d\n", RTA_LEN(attr)); break; default: rta_fmt(attr, "0x%x", attr->rta_type); break; } } }