/*************************************************************************/ /* ip.c ip.c */ /*************************************************************************/ /* ip.c prints out IP and ARP packets in human readable form */ /* AUTHOR: Vance Morrison DATE: 6/5/90 */ static char copywrite[] = "Copywrite (c) 1990, Vance Morrison"; /*************************************************************************/ #include #include #include #define swap_word(n) ((((unsigned short) n) >> 8)+(((unsigned short) n) << 8)) #define ARP_REQUEST 1 #define ARP_REPLY 2 #define ARP_ETHER_TYPE 1 struct arp { unsigned short arp_hdr; /* header type 1 = ETHERNET */ unsigned short arp_proto; /* protocol code */ unsigned char arp_hln; /* length of ethernet address */ unsigned char arp_pln; /* length of ethernet address */ unsigned short arp_op; /* operation (request reply) */ unsigned char arp_sha[6]; /* source hardware address */ unsigned char arp_spa[4]; /* source protocol address */ unsigned char arp_tha[6]; /* target hardware address */ unsigned char arp_tpa[4]; /* target protocol address */ }; #define IP_PROTO_ICMP 1 #define IP_PROTO_TCP 6 #define IP_PROTO_UDP 17 struct ip { unsigned char ip_ver_size; unsigned char ip_tos; unsigned short ip_length; unsigned short ip_id; unsigned short ip_frag; unsigned char ip_ttl; unsigned char ip_proto; unsigned short ip_check; unsigned char ip_src[4]; unsigned char ip_dst[4]; unsigned char ip_data[1]; }; struct udp { unsigned short udp_src; unsigned short udp_dst; unsigned short udp_length; unsigned short udp_check; unsigned char udp_data[1]; }; /* values for type field */ #define ICMP_ECHO_REPLY 0 #define ICMP_ECHO_REQUEST 8 #define ICMP_TIME 11 #define ICMP_UNREACHABLE 3 #define ICMP_REDIRECT 5 /* values for the code field */ #define ICMP_TIME_TTL 0 #define ICMP_UNREACH_NET 0 #define ICMP_UNREACH_HOST 1 #define ICMP_UNREACH_PROTO 2 #define ICMP_UNREACH_PORT 3 #define ICMP_REDIRECT_NET 0 #define ICMP_REDIRECT_HOST 1 #define ICMP_REDIRECT_TOS_NET 2 #define ICMP_REDIRECT_TOS_HOST 3 struct icmp { unsigned char icmp_type; unsigned char icmp_code; unsigned short icmp_check; unsigned short icmp_id; unsigned short icmp_seq; }; /* definition of RIP packet structure */ #define RIP_PORT 0x208 #define RIP_REPLY 2 #define IP_FAMILY 2 struct rip_route { unsigned short rip_family; unsigned short rip_zero1; unsigned char rip_address[4]; unsigned char rip_zero2[4]; unsigned char rip_zero3[4]; unsigned char rip_metric[4]; }; struct rip { unsigned char rip_command; unsigned char rip_version; unsigned short rip_zero; struct rip_route rip_routes[1]; /* routing info */ }; struct tcp { unsigned short tcp_src; unsigned short tcp_dst; unsigned long tcp_seq; unsigned long tcp_ack; unsigned char tcp_off; unsigned char tcp_flags; unsigned short tcp_window; unsigned short tcp_check; unsigned short tcp_urgent; unsigned char tcp_data[1]; }; /******************************************************************/ print_IP_addr(ip_addr) unsigned char *ip_addr; { char buff[20]; sprintf(buff, "%d.%d.%d.%d",ip_addr[0],ip_addr[1],ip_addr[2],ip_addr[3]); printf("%15s", buff); } /******************************************************************/ print_arp(p) struct arp *p; { unsigned short op; printf(" ARP PACKET\n"); printf(" TYPE: %d ", swap_word(p->arp_hdr)); op = swap_word(p->arp_op); printf(" OP: %d ", op); if (op == ARP_REQUEST) printf("(REQUEST) "); else if (op == ARP_REPLY) printf("(REPLY) "); else printf("(UNKNOWN) "); printf("\n"); printf(" SOURCE: ETHER "); print_ether_addr(p->arp_sha); printf(" IP "); print_IP_addr(p->arp_spa); printf("\n"); printf(" TARGET: ETHER "); print_ether_addr(p->arp_tha); printf(" IP "); print_IP_addr(p->arp_tpa); printf("\n"); } /******************************************************************/ /* computes the ones complement some of a block of numbers (assumes a twos complement 16 bit short integer) */ ones_comp_sum(p, len) unsigned short *p; int len; { register unsigned short sum; register unsigned short new_sum; sum = 0; while (len > 0) { new_sum = sum + *p++; if (new_sum < sum) /* did we wrap around */ new_sum++; sum = new_sum; --len; } return(sum); } /**************************************************************************/ /* pseudo_head_sum, computes the checksum for the psuedo-header given a IP packet. This number is used for TCP and UDP checksumming */ unsigned short pseudo_head_sum(p) struct ip *p; { unsigned short data_len; unsigned short check; unsigned char ttl; unsigned short ret; check = p->ip_check; ttl = p->ip_ttl; p->ip_ttl = 0; data_len = swap_word(p->ip_length) - 4*(p->ip_ver_size%16); p->ip_check = swap_word(data_len); ret = ones_comp_sum((unsigned short *) &p->ip_ttl, 6); p->ip_check = check; p->ip_ttl = ttl; return(ret); } /******************************************************************/ print_ip(p) struct ip *p; { unsigned short check, my_check; printf(" IP PACKET "); print_IP_addr(p->ip_src); printf(" --> "); print_IP_addr(p->ip_dst); printf("\n"); printf(" VER:%2d SIZE:%2d ID: %4xH TOS:%3d FRAG/FLAGS: %4xH\n" ,(p->ip_ver_size / 16), (p->ip_ver_size % 16), swap_word(p->ip_id), p->ip_tos, swap_word(p->ip_frag)); printf(" LEN:%4d TTL:%3d PROTOCOL:%4d ", swap_word(p->ip_length), p->ip_ttl, p->ip_proto); switch (p->ip_proto) { case IP_PROTO_ICMP: printf("(ICMP)"); break; case IP_PROTO_TCP: printf("(TCP) "); break; case IP_PROTO_UDP: printf("(UDP) "); break; default: printf(" "); break; } check = p->ip_check; p->ip_check = 0; my_check = ~ones_comp_sum((unsigned short *) p, 10); p->ip_check = check; printf(" CHECK: %4xH ", swap_word(check)); if (check == 0) printf("(Ignored) "); else if (check == my_check) printf("(Correct) "); else printf("(Should be %4x)", swap_word(my_check)); printf("\n"); switch (p->ip_proto) { case IP_PROTO_ICMP: print_icmp((struct icmp *) p->ip_data); break; case IP_PROTO_TCP: print_tcp((struct tcp *) p->ip_data, swap_word(p->ip_length)-4*(p->ip_ver_size%16)); break; case IP_PROTO_UDP: print_udp((struct udp *) p->ip_data); break; default: break; } } /******************************************************************/ print_udp(p) struct udp *p; { printf(" UDP PACKET\n"); printf(" LEN:%4d SOURCE: %3d DEST %3d: CHECK: %4xH\n", swap_word(p->udp_length), swap_word(p->udp_src), swap_word(p->udp_dst), swap_word(p->udp_check)); switch (swap_word(p->udp_dst)) { case RIP_PORT: print_rip((struct rip *) p->udp_data, swap_word(p->udp_length)-8); break; default: break; } } /******************************************************************/ print_tcp(p, len) struct tcp *p; int len; { printf(" TCP PACKET\n"); printf(" LEN:%4d SOURCE: %3d DEST %3d: CHECK: %4xH\n", len - 20, swap_word(p->tcp_src), swap_word(p->tcp_dst), swap_word(p->tcp_check)); } /******************************************************************/ print_icmp(p) struct icmp *p; { printf(" ICMP PACKET\n"); printf(" TYPE:%3d", p->icmp_type); switch (p->icmp_type) { case ICMP_ECHO_REPLY: printf("(ECHO REPLY) "); break; case ICMP_ECHO_REQUEST: printf("(ECHO REQUEST) "); break; case ICMP_TIME: printf("(TIME) "); break; case ICMP_UNREACHABLE: printf("(UNREACHABLE) "); break; case ICMP_REDIRECT: printf("(REDIRECT) "); break; default: printf("(UNKNOWN) "); break; } printf(" CODE:%3d", p->icmp_code); } /******************************************************************/ print_rip(p, len) struct rip *p; int len; { int i, num_routes; printf(" RIP PACKET\n"); printf(" COMMAND:%3d VERSION:%3d\n", p->rip_command, p->rip_version); num_routes = (len - 4)/20; for(i = 0; i < num_routes; i++) { printf(" ROUTE: "); print_IP_addr(p->rip_routes[i].rip_address); printf(" METRIC:%3d", p->rip_routes[i].rip_metric[3]); printf(" FAMILY:%3d\n", swap_word(p->rip_routes[i].rip_family)); } }