/* * $Id: nemesis-printout.c,v 1.1.1.1 2003/10/31 21:29:37 jnathan Exp $ * * THE NEMESIS PROJECT * Copyright (C) 2002, 2003 Jeff Nathan * * nemesis-functions.c (nemesis utility functions) * */ #if defined(HAVE_CONFIG_H) #include "config.h" #endif #include #include #include #if defined(WIN32) #include #endif #include #if defined(HAVE_LIMITS_H) || defined(WIN32) #include #endif #if defined(HAVE_ERRNO_H) || defined(WIN32) #include #endif #if defined(HAVE_NETINET_IN_H) #include #elif defined(WIN32) #include #include #endif #include #include "nemesis.h" /** * Dumps a packet payload in hex format * * @param buf pointer to allocated payload memory * @param len length of buffer to print in hex format * * @notes Contributed by Dragos Ruiu . A very nice piece of code. * * @return void function */ void nemesis_hexdump(char *buf, u_int32_t len, int mode) { int c, linemod; char *p, *l, *dump, *predump, *postdump, dumpbuf[40]; l = &(buf[len - 1]); dump = dumpbuf; putchar('\n'); switch (mode) { case HEX_RAW_DECODE: linemod = 26; predump = " "; postdump = ""; break; case HEX_ASCII_DECODE: /* FALLTHROUGH */ default: linemod = 16; predump = " "; postdump = " "; break; } STPUTS("[Hexdump]\n"); for (p = buf; p <= l; p++) { *(dump++) = (isprint((int)*p) ? *p : '.'); putchar((c = (*p & 0xF0) >> 4) < 10 ? c + '0' : c + '7'); putchar((c = *p & 0x0F) < 10 ? c + '0' : c + '7'); if (!(((p - buf) + 1) % linemod) || (p == l)) { /* pad the last line */ if (p == l) { while (((((p++) - buf) + 1) % linemod)) { STPUTS(predump); } } *dump = 0; STPUTS(postdump); if (mode == HEX_ASCII_DECODE) puts(dumpbuf); else putchar('\n'); dump = dumpbuf; } else putchar(' '); } putchar('\n'); } /** * Print the source and destination within the supplied ETHERhdr struct in * ASCII form. * * @param eth pointer to an ETHERhdr struct * * @return void function */ void nemesis_printeth(ETHERhdr *eth) { char *ethertype = "Unknown"; switch (eth->ether_type) { case ETHERTYPE_PUP: ethertype = "PUP"; break; case ETHERTYPE_IP: ethertype = "IP"; break; case ETHERTYPE_ARP: ethertype = "ARP"; break; case ETHERTYPE_REVARP: ethertype = "RARP"; break; case ETHERTYPE_VLAN: ethertype = "802.1q"; break; case ETHERTYPE_IPV6: ethertype = "IPv6"; break; case 34915: ethertype = "PPOE discovery"; break; case 34916: ethertype = "PPOE session"; break; default: break; } printf(" [MAC] %02X:%02X:%02X:%02X:%02X:%02X > " "%02X:%02X:%02X:%02X:%02X:%02X\n", eth->ether_shost[0], eth->ether_shost[1], eth->ether_shost[2], eth->ether_shost[3], eth->ether_shost[4], eth->ether_shost[5], eth->ether_dhost[0], eth->ether_dhost[1], eth->ether_dhost[2], eth->ether_dhost[3], eth->ether_dhost[4], eth->ether_dhost[5]); printf(" [Ethernet type] %s (%#.4x)\n\n", ethertype, eth->ether_type); return; } /** * Verbosely print portions of the ARP header in ASCII form. * * @param arp pointer to an ARPhdr struct * * @return void function */ void nemesis_printarp(ARPhdr *arp) { char *src = NULL, *dst = NULL; char *opcode = "Unknown"; switch (arp->ar_op) { case ARPOP_REQUEST: opcode = "Request"; break; case ARPOP_REPLY: opcode = "Reply"; break; case ARPOP_REVREQUEST: opcode = "Reverse request"; break; case ARPOP_REVREPLY: opcode = "Reverse reply"; break; } src = strdup(inet_ntoa(*(struct in_addr *)&arp->ar_spa)); dst = strdup(inet_ntoa(*(struct in_addr *)&arp->ar_tpa)); printf(" [Protocol addr:IP] %s > %s\n", src, dst); printf(" [Hardware addr:MAC] %02x:%02x:%02x:%02x:%02x:%02x > " "%02X:%02X:%02X:%02X:%02X:%02X\n", arp->ar_sha[0], arp->ar_sha[1], arp->ar_sha[2], arp->ar_sha[3], arp->ar_sha[4], arp->ar_sha[5], arp->ar_tha[0], arp->ar_tha[1], arp->ar_tha[2], arp->ar_tha[3], arp->ar_tha[4], arp->ar_tha[5]); printf(" [ARP opcode] %s\n", opcode); printf(" [ARP hardware fmt] %s (%hu)\n", "Ethernet", arp->ar_hrd); printf(" [ARP proto format] %s (%#.4x)\n", "IP", arp->ar_pro); printf(" [ARP protocol len] %d\n", arp->ar_hln); printf(" [ARP hardware len] %d\n\n", arp->ar_pln); if (src != NULL) free(src); if (dst != NULL) free(dst); return; } /** * Verbosely print portions of the IP header in ASCII form. * * @param ip pointer to an IPhdr struct * * @return void function */ void nemesis_printip(IPhdr *ip) { char *protoname = "Unknown"; char *src = NULL, *dst = NULL; src = strdup(inet_ntoa(ip->ip_src)); dst = strdup(inet_ntoa(ip->ip_dst)); printf(" [IP] %s > %s\n", src, dst); printf(" [IP ID] %hu\n", ip->ip_id); switch(ip->ip_p) { case 0: protoname = "IP"; break; case 1: protoname = "ICMP"; break; case 2: protoname = "IGMP"; break; case 3: protoname = "GGP"; break; case 4: protoname = "IP-ENCAP"; break; case 5: protoname = "ST"; break; case 6: protoname = "TCP"; break; case 7: protoname = "UCL"; break; case 8: protoname = "EGP"; break; case 9: protoname = "IGP"; break; case 10: protoname = "BBN-RCC-MON"; break; case 11: protoname = "NVP-II"; break; case 12: protoname = "PUP"; break; case 13: protoname = "ARGUS"; break; case 14: protoname = "EMCON"; break; case 15: protoname = "XNET"; break; case 16: protoname = "CHAOS"; break; case 17: protoname = "UDP"; break; case 18: protoname = "MUX"; break; case 19: protoname = "DCN-MEAS"; break; case 20: protoname = "HMP"; break; case 21: protoname = "PRM"; break; case 22: protoname = "XNS-IDP"; break; case 23: protoname = "TRUNK-1"; break; case 24: protoname = "TRUNK-2"; break; case 25: protoname = "LEAF-1"; break; case 26: protoname = "LEAF-2"; break; case 27: protoname = "RDP"; break; case 28: protoname = "IRTP"; break; case 29: protoname = "ISO-TP4"; break; case 30: protoname = "NETBLT"; break; case 31: protoname = "MFE-NSP"; break; case 32: protoname = "MERIT-INP"; break; case 33: protoname = "SEP"; break; case 34: protoname = "3PC"; break; case 35: protoname = "IDPR"; break; case 36: protoname = "XTP"; break; case 37: protoname = "DDP"; break; case 38: protoname = "IDPR-CMTP"; break; case 39: protoname = "IDPR-CMTP"; break; case 40: protoname = "IL"; break; case 41: protoname = "IPv6"; break; case 42: protoname = "SDRP"; break; case 43: protoname = "SIP-SR"; break; case 44: protoname = "SIP-FRAG"; break; case 45: protoname = "IDRP"; break; case 46: protoname = "RSVP"; break; case 47: protoname = "GRE"; break; case 48: protoname = "MHRP"; break; case 49: protoname = "BNA"; break; case 50: protoname = "IPSEC-ESP"; break; case 51: protoname = "IPSEC-AH"; break; case 52: protoname = "I-NLSP"; break; case 53: protoname = "SWIPE"; break; case 54: protoname = "NHRP"; break; case 55: protoname = "MOBILEIP"; break; case 57: protoname = "SKIP"; break; case 58: protoname = "IPv6-ICMP"; break; case 59: protoname = "IPv6-NoNxt"; break; case 60: protoname = "IPv6-Opts"; break; case 61: protoname = "any"; break; case 62: protoname = "CFTP"; break; case 63: protoname = "any"; break; case 64: protoname = "SAT-EXPAK"; break; case 65: protoname = "KRYPTOLAN"; break; case 66: protoname = "RVD"; break; case 67: protoname = "IPPC"; break; case 68: protoname = "any"; break; case 69: protoname = "SAT-MON"; break; case 70: protoname = "VISA"; break; case 71: protoname = "IPCV"; break; case 72: protoname = "CPNX"; break; case 73: protoname = "CPHB"; break; case 74: protoname = "WSN"; break; case 75: protoname = "PVP"; break; case 76: protoname = "BR-SAT-MON"; break; case 77: protoname = "SUN-ND"; break; case 78: protoname = "WB-MON"; break; case 79: protoname = "WB-EXPAK"; break; case 80: protoname = "ISO-IP"; break; case 81: protoname = "VMTP"; break; case 82: protoname = "SECURE-VMTP"; break; case 83: protoname = "VINES"; break; case 84: protoname = "TTP"; break; case 85: protoname = "NSFNET-IGP"; break; case 86: protoname = "DGP"; break; case 87: protoname = "TCF"; break; case 88: protoname = "IGRP"; break; case 89: protoname = "OSPFIGP"; break; case 90: protoname = "Sprite-RPC"; break; case 91: protoname = "LARP"; break; case 92: protoname = "MTP"; break; case 93: protoname = "AX.25"; break; case 94: protoname = "IPIP"; break; case 95: protoname = "MICP"; break; case 96: protoname = "SCC-SP"; break; case 97: protoname = "ETHERIP"; break; case 98: protoname = "ENCAP"; break; case 99: protoname = "any"; break; case 100: protoname = "GMTP"; break; case 103: protoname = "PIM"; break; case 108: protoname = "IPComp"; break; case 112: protoname = "VRRP"; break; case 255: protoname = "Reserved"; break; } printf(" [IP Proto] %s (%hu)\n", protoname, ip->ip_p); printf(" [IP TTL] %u\n", ip->ip_ttl); printf(" [IP TOS] 0x%.2x\n", ip->ip_tos); printf(" [IP Frag offset] 0x%.4x\n", ip->ip_off & IP_OFFMASK); STPUTS(" [IP Frag flags] "); if ((ip->ip_off & IP_RF) >> 15) STPUTS("RESERVED "); if ((ip->ip_off & IP_DF) >> 14) STPUTS("DF "); if ((ip->ip_off & IP_MF) >> 13) STPUTS("MF "); putchar('\n'); if (src != NULL) free(src); if (dst != NULL) free(dst); return; } /** * Verbosely print portions of the TCP header in ASCII form. * * @param tcp TCPhdr struct * * @return void function */ void nemesis_printtcp(TCPhdr *tcp) { printf(" [TCP Ports] %hu > %hu\n", tcp->th_sport, tcp->th_dport); STPUTS(" [TCP Flags] "); if (tcp->th_flags & TH_SYN) STPUTS("SYN "); if (tcp->th_flags & TH_ACK) STPUTS("ACK "); if (tcp->th_flags & TH_RST) STPUTS("RST "); if (tcp->th_flags & TH_PUSH) STPUTS("PSH "); if (tcp->th_flags & TH_URG) STPUTS("URG "); if (tcp->th_flags & TH_FIN) STPUTS("FIN "); if (tcp->th_flags & TH_ECE) STPUTS("ECE "); if (tcp->th_flags & TH_CWR) STPUTS("CWR "); putchar('\n'); printf("[TCP Urgent Pointer] %u\n", tcp->th_urp); printf(" [TCP Window Size] %u\n", tcp->th_win); if (tcp->th_flags & TH_ACK) printf(" [TCP Ack number] %lu\n", tcp->th_ack); if (tcp->th_flags & TH_SYN) printf(" [TCP Seq number] %lu\n", tcp->th_seq); putchar('\n'); return; } /** * Verbosely print portions of the UDP header in ASCII form. * * @param udp UDPhdr struct * * @return void function */ void nemesis_printudp(UDPhdr *udp) { printf(" [UDP Ports] %hu > %hu\n\n", udp->uh_sport, udp->uh_dport); return; } /** * Verbosely print portions of the ICMP header in ASCII form. * * @param icmp ICMPhdr struct * @param mode ICMP injection mode * * @return void function */ void nemesis_printicmp(ICMPhdr *icmp, int mode) { char *icmptype = "Unknown"; char *icmpcode = "Unknown"; char *mask = NULL, *gateway = NULL; mask = strdup(inet_ntoa(*(struct in_addr *)&icmp->dun.mask)); gateway = strdup(inet_ntoa(*(struct in_addr *)&icmp->hun.gateway)); switch (icmp->icmp_type) { case 0: icmptype = "Echo Reply"; if (icmp->icmp_code == 0) icmpcode = "Echo Reply"; break; case 3: icmptype = "Destination Unreachable"; switch (icmp->icmp_code) { case 0: icmpcode = "Network Unreachable"; break; case 1: icmpcode = "Host Unreachable"; break; case 2: icmpcode = "Protocol Unreachable"; break; case 3: icmpcode = "Port Unreachable"; break; case 4: icmpcode = "Fragmentation Needed"; break; case 5: icmpcode = "Source Route Failed"; break; case 6: icmpcode = "Destination Network Unknown"; break; case 7: icmpcode = "Destination Host Unknown"; break; case 8: icmpcode = "Source Host Isolated (obsolete)"; break; case 9: icmpcode = "Destination Network Administratively " "Prohibited"; break; case 10: icmpcode = "Destination Host Administratively " "Prohibited"; break; case 11: icmpcode = "Network Unreachable For TOS"; break; case 12: icmpcode = "Host Unreachable For TOS"; break; case 13: icmpcode = "Communication Administratively Prohibited " "By Filtering"; break; case 14: icmpcode = "Host Precedence Violation"; break; case 15: icmpcode = "Precedence Cutoff In Effect"; break; default: break; } break; case 4: icmptype = "Source Quench"; if (icmp->icmp_code == 0) icmpcode = "Source Quench"; break; case 5: icmptype = "Redirect"; switch (icmp->icmp_code) { case 0: icmpcode = "Redirect For Network"; break; case 1: icmpcode = "Redirect For Host"; break; case 2: icmpcode = "Redirect For TOS and Network"; break; case 3: icmpcode = "Redirect For TOS and Host"; break; default: break; } break; case 8: icmptype = "Echo Request"; if (icmp->icmp_code == 0) icmpcode = "Echo Request"; break; case 9: icmptype = "Router Advertisement"; if (icmp->icmp_code == 0) icmpcode = "Router Advertisement"; break; case 10: icmptype = "Router Solicitation"; if (icmp->icmp_code == 0) icmpcode = "Router Solicitation"; break; case 11: icmptype = "Time Exceeded"; switch (icmp->icmp_code) { case 0: icmpcode = "TTL = 0 During Transmit"; break; case 1: icmpcode = "TTL = 0 During Reassembly"; break; default: break; } break; case 12: icmptype = "Parameter Problem"; switch (icmp->icmp_code) { case 0: icmpcode = "IP Header Bad (catchall error)"; break; case 1: icmpcode = "Required Option Missing"; break; default: break; } case 13: icmptype = "Timestamp Request"; if (icmp->icmp_code == 0) icmpcode = "Timestamp Request"; break; case 14: icmpcode = "Timestamp Reply"; if (icmp->icmp_code == 0) icmpcode = "Timestamp Reply"; break; case 15: icmptype = "Information Request"; if (icmp->icmp_code == 0) icmpcode = "Information Request"; break; case 16: icmptype = "Information Reply"; if (icmp->icmp_code == 0) icmpcode = "Information Reply"; break; case 17: icmptype = "Address Mask Request"; if (icmp->icmp_code == 0) icmpcode = "Address Mask Request"; break; case 18: icmptype = "Address Mask Reply"; if (icmp->icmp_code == 0) icmptype = "Address Mask Reply"; break; default: icmptype = "Unknown"; break; } printf(" [ICMP Type] %s\n", icmptype); printf(" [ICMP Code] %s\n", icmpcode); if (mode == ICMP_ECHO || mode == ICMP_MASKREQ || mode == ICMP_TSTAMP) { printf(" [ICMP ID] %hu\n", icmp->hun.echo.id); printf(" [ICMP Seq number] %hu\n", icmp->hun.echo.seq); } if (mode == ICMP_MASKREQ) printf(" [ICMP Address Mask] %s\n", mask); if (mode == ICMP_REDIRECT) printf(" [ICMP Pref Gateway] %s\n", gateway); putchar('\n'); if (mask != NULL) free(mask); if (gateway != NULL) free(gateway); return; } /** * Verbosely print portions of the RIP header in ASCII form. * * @param rip pointer to a RIPhdr struct * * @return void function * */ void nemesis_printrip(RIPhdr *rip) { char *cmd = "Unknown"; char *family = "Unknown"; char *addr = NULL, *mask = NULL, *hop = NULL; addr = strdup(inet_ntoa(*(struct in_addr *)&rip->addr)); mask = strdup(inet_ntoa(*(struct in_addr *)&rip->mask)); hop = strdup(inet_ntoa(*(struct in_addr *)&rip->next_hop)); switch(rip->cmd) { case RIPCMD_REQUEST: cmd = "Request"; break; case RIPCMD_RESPONSE: cmd = "Response"; break; case RIPCMD_TRACEON: cmd = "Tracing on (obsolete)"; break; case RIPCMD_TRACEOFF: cmd = "Tracing off (obsolete)"; break; case RIPCMD_POLL: cmd = "Poll"; break; case RIPCMD_POLLENTRY: cmd = "Poll entry"; break; case RIPCMD_MAX: cmd = "Max"; break; default: break; } printf(" [RIP Command] %s (%hu)\n", cmd, (u_int16_t)rip->cmd); printf(" [RIP Version] %hu\n", (u_int16_t)rip->ver); printf("[RIP Routing domain] %hu\n", (u_int16_t)rip->rd); if (rip->af == 2) family = "IP"; printf("[RIP Address family] %s (%hu)\n", family, (u_int16_t)rip->af); printf(" [RIP Route tag] %hu\n", (u_int16_t)rip->rt); printf(" [RIP Address] %s\n", addr); printf(" [RIP Network mask] %s\n", mask); printf(" [RIP Next hop] %s\n", hop); printf(" [RIP Metric] %u\n", (u_int32_t)rip->metric); putchar('\n'); if (addr != NULL) free(addr); if (mask != NULL) free(mask); if (hop != NULL) free(hop); return; } /** * Verbosely print portions of the OSPF header in ASCII form. * * @param opsf OSPfhdr struct * * @return void function */ void nemesis_printospf(OSPFhdr *ospf) { char *type = ""; char *auth_type = "Unknown"; char *rtr_id = NULL, *area_id = NULL; rtr_id = strdup(inet_ntoa(*(struct in_addr *)&ospf->ospf_rtr_id.s_addr)); area_id = strdup(inet_ntoa(*(struct in_addr *)&ospf->ospf_area_id.s_addr)); switch(ospf->ospf_type) { case LIBNET_OSPF_HELLO: type = "Hello"; break; case LIBNET_OSPF_DBD: type = "Database Description"; break; case LIBNET_OSPF_LSR: type = "Link State Request"; break; case LIBNET_OSPF_LSU: type = "Link State Update"; break; case LIBNET_OSPF_LSA: type = "Link State Acknowledgement"; break; } switch(ntohs(ospf->ospf_auth_type)) { case LIBNET_OSPF_AUTH_NULL: auth_type = "None"; break; case LIBNET_OSPF_AUTH_SIMPLE: auth_type = "Simple password"; break; case LIBNET_OSPF_AUTH_MD5: auth_type = "MD5"; break; } printf(" [OSPF Type] %s\n", type); printf("[OSPF src router ID] %s\n", rtr_id); printf(" [OSPF area ID] %s\n", area_id); printf(" [OSPF auth type] %s\n", auth_type); putchar('\n'); if (type != NULL) free(type); if (rtr_id != NULL) free(rtr_id); if (area_id != NULL) free(area_id); if (auth_type != NULL) free(auth_type); return; } /** * Build the title string for each nemesis protocol builder. * * @param title the buffer containing the concatenated title * @param module the name of the protocol builder module * @param version release version * * @return void function */ void nemesis_maketitle(char *title, const char *module, const char *version) { char tmptitle[TITLEBUFFSIZE], buildnum[13]; strlcpy(tmptitle, module, sizeof(tmptitle)); /* strlcat(char *dst, const char *src, size_t size) automatically uses * size - strlen(dst) - 1 for size argument */ strlcat(tmptitle, version, sizeof(tmptitle)); snprintf(buildnum, sizeof(buildnum), " (Build %d)", BUILD); strlcat(tmptitle, buildnum, sizeof(tmptitle)); memcpy(title, tmptitle, sizeof(tmptitle)); } /** * Print the title string for each nemesis protocol builder. * * @param title the buffer containing the concatenated title * * @return void function */ void nemesis_printtitle(const char *title) { putchar('\n'); puts(title); putchar('\n'); return; } /** * Print an error when an Ethernet device can't be opened for link-layer * injection. * * @param errmsg the buffer containing the error message * * @return void function */ void nemesis_device_failure(int mode, const char *device) { if (mode == INJECTION_RAW) fprintf(stderr, "ERROR: Unable to open raw socket for packet " "injection: %s.\n", errbuf); else if (mode == INJECTION_LINK && device != NULL && errbuf != NULL) fprintf(stderr, "ERROR: Unable to open layer 2 device '%s' for packet " "injection: %s.\n", device, errbuf); #if !defined(WIN32) fprintf(stderr, "You may need root privileges to use nemesis.\n"); #else fprintf(stderr, "You may need Administrator privileges to use nemesis.\n"); #endif return; }