static char *fd_addr_tostr(char *buf, size_t len, int af, void *addr) { char tmp[128]; if(addr == NULL || addr_tostr(af, addr, tmp, sizeof(tmp)) == NULL) return ""; snprintf(buf, len, " %s", tmp); return buf; }
void scamper_icmp_resp_print(const scamper_icmp_resp_t *ir) { char *t = NULL, tbuf[64]; char *c = NULL, cbuf[64]; char addr[64]; char ip[256]; char icmp[256]; char inner_ip[256]; char inner_transport[256]; char ext[256]; int i, j; size_t off; assert(ir->ir_af == AF_INET || ir->ir_af == AF_INET6); if(ir->ir_af == AF_INET) { addr_tostr(AF_INET, &ir->ir_ip_src.v4, addr, sizeof(addr)); off = 0; string_concat(ip, sizeof(ip), &off, "from %s size %d ttl %d tos 0x%02x ipid 0x%04x", addr, ir->ir_ip_size, ir->ir_ip_ttl, ir->ir_ip_tos, ir->ir_ip_id); if(ir->ir_ipopt_rrc > 0) string_concat(ip, sizeof(ip), &off, " rr %d", ir->ir_ipopt_rrc); switch(ir->ir_icmp_type) { case ICMP_UNREACH: t = "unreach"; switch(ir->ir_icmp_code) { case ICMP_UNREACH_NET: c = "net"; break; case ICMP_UNREACH_HOST: c = "host"; break; case ICMP_UNREACH_PROTOCOL: c = "protocol"; break; case ICMP_UNREACH_PORT: c = "port"; break; case ICMP_UNREACH_SRCFAIL: c = "src-rt failed"; break; case ICMP_UNREACH_NET_UNKNOWN: c = "net unknown"; break; case ICMP_UNREACH_HOST_UNKNOWN: c = "host unknown"; break; case ICMP_UNREACH_ISOLATED: c = "isolated"; break; case ICMP_UNREACH_NET_PROHIB: c = "net prohib"; break; case ICMP_UNREACH_HOST_PROHIB: c = "host prohib"; break; case ICMP_UNREACH_TOSNET: c = "tos net"; break; case ICMP_UNREACH_TOSHOST: c = "tos host"; break; case ICMP_UNREACH_FILTER_PROHIB: c = "admin prohib"; break; case ICMP_UNREACH_NEEDFRAG: /* * use the type buf to be consistent with the ICMP6 * fragmentation required message */ snprintf(tbuf, sizeof(tbuf), "need frag %d", ir->ir_icmp_nhmtu); t = tbuf; break; default: snprintf(cbuf, sizeof(cbuf), "code %d", ir->ir_icmp_code); c = cbuf; break; } break; case ICMP_TIMXCEED: t = "time exceeded"; switch(ir->ir_icmp_code) { case ICMP_TIMXCEED_INTRANS: c = "in trans"; break; case ICMP_TIMXCEED_REASS: c = "in reass"; break; default: snprintf(cbuf, sizeof(cbuf), "code %d", ir->ir_icmp_code); c = cbuf; break; } break; case ICMP_ECHOREPLY: t = "echo reply"; snprintf(cbuf, sizeof(cbuf), "id %d seq %d", ir->ir_icmp_id, ir->ir_icmp_seq); c = cbuf; break; case ICMP_TSTAMPREPLY: t = "ts reply"; snprintf(cbuf, sizeof(cbuf), "id %d seq %d", ir->ir_icmp_id, ir->ir_icmp_seq); c = cbuf; break; } } else /* if(ir->ir_af == AF_INET6) */ { addr_tostr(AF_INET6, &ir->ir_ip_src.v6, addr, sizeof(addr)); snprintf(ip, sizeof(ip), "from %s size %d hlim %d", addr, ir->ir_ip_size, ir->ir_ip_hlim); switch(ir->ir_icmp_type) { case ICMP6_DST_UNREACH: t = "unreach"; switch(ir->ir_icmp_code) { case ICMP6_DST_UNREACH_NOROUTE: c = "no route"; break; case ICMP6_DST_UNREACH_ADMIN: c = "admin prohib"; break; case ICMP6_DST_UNREACH_BEYONDSCOPE: c = "beyond scope"; break; case ICMP6_DST_UNREACH_ADDR: c = "addr"; break; case ICMP6_DST_UNREACH_NOPORT: c = "port"; break; default: snprintf(cbuf, sizeof(cbuf), "code %d", ir->ir_icmp_code); c = cbuf; break; } break; case ICMP6_TIME_EXCEEDED: t = "time exceeded"; switch(ir->ir_icmp_code) { case ICMP6_TIME_EXCEED_TRANSIT: c = "in trans"; break; case ICMP6_TIME_EXCEED_REASSEMBLY: c = "in reass"; break; default: snprintf(cbuf, sizeof(cbuf), "code %d", ir->ir_icmp_code); c = cbuf; break; } break; case ICMP6_PACKET_TOO_BIG: snprintf(tbuf, sizeof(tbuf), "need frag %d", ir->ir_icmp_nhmtu); t = tbuf; break; case ICMP6_ECHO_REPLY: t = "echo reply"; snprintf(cbuf, sizeof(cbuf), "id %d seq %d", ir->ir_icmp_id, ir->ir_icmp_seq); c = cbuf; break; } } if(t == NULL) { snprintf(icmp, sizeof(icmp), "icmp %d code %d", ir->ir_icmp_type, ir->ir_icmp_code); } else if(c == NULL) { snprintf(icmp, sizeof(icmp), "icmp %s", t); } else { snprintf(icmp, sizeof(icmp), "icmp %s %s", t, c); } if(ir->ir_flags & SCAMPER_ICMP_RESP_FLAG_INNER_IP) { if(ir->ir_af == AF_INET) { addr_tostr(AF_INET, &ir->ir_inner_ip_dst.v4, addr, sizeof(addr)); off = 0; string_concat(inner_ip, sizeof(inner_ip), &off, " to %s size %d ttl %d tos 0x%02x ipid 0x%04x", addr, ir->ir_inner_ip_size, ir->ir_inner_ip_ttl, ir->ir_inner_ip_tos, ir->ir_inner_ip_id); if(ir->ir_inner_ipopt_rrc > 0) string_concat(inner_ip, sizeof(inner_ip), &off, " rr %d", ir->ir_inner_ipopt_rrc); } else /* if(ir->ir_af == AF_INET6) */ { addr_tostr(AF_INET6, &ir->ir_inner_ip_dst.v6, addr, sizeof(addr)); snprintf(inner_ip, sizeof(inner_ip), " to %s size %d hlim %d flow 0x%05x", addr, ir->ir_inner_ip_size, ir->ir_inner_ip_hlim, ir->ir_inner_ip_flow); } switch(ir->ir_inner_ip_proto) { case IPPROTO_UDP: snprintf(inner_transport, sizeof(inner_transport), " proto UDP sport %d dport %d sum 0x%04x", ir->ir_inner_udp_sport, ir->ir_inner_udp_dport, ntohs(ir->ir_inner_udp_sum)); break; case IPPROTO_ICMP: case IPPROTO_ICMPV6: snprintf(inner_transport, sizeof(inner_transport), " proto ICMP type %d code %d id %04x seq %d sum %04x", ir->ir_inner_icmp_type, ir->ir_inner_icmp_code, ir->ir_inner_icmp_id, ir->ir_inner_icmp_seq, ntohs(ir->ir_inner_icmp_sum)); break; case IPPROTO_TCP: snprintf(inner_transport, sizeof(inner_transport), " proto TCP sport %d dport %d seq %08x", ir->ir_inner_tcp_sport, ir->ir_inner_tcp_dport, ir->ir_inner_tcp_seq); break; default: inner_transport[0] = '\0'; break; } } else { inner_ip[0] = '\0'; inner_transport[0] = '\0'; } if(ir->ir_ext != NULL) { snprintf(ext, sizeof(ext), " icmp-ext"); j = 9; for(i=0; i<ir->ir_extlen; i++) { if(i % 4 == 0) { if(sizeof(ext)-j < 4) break; ext[j++] = ' '; } else if(sizeof(ext)-j < 3) break; byte2hex(ir->ir_ext[i], ext + j); j += 2; } ext[j] = '\0'; } else { ext[0] = '\0'; } scamper_debug(NULL, "%s %s%s%s%s", ip, icmp, inner_ip, inner_transport, ext); return; }