/* * Copyright (c) 2004 Rinet Corp., Novosibirsk, Russia * * Redistribution and use in source forms, with and without modification, * are permitted provided that this entire comment appears intact. * * THIS SOURCE CODE IS PROVIDED ``AS IS'' WITHOUT ANY WARRANTIES OF ANY KIND. */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #ifdef INET6 #include #include #endif #include "parse_ip.h" #include "netstat.h" int parse_ip(ns, caplen, ip) NETSTAT *ns; int caplen; const struct ip *ip; { int hdrlen = 0, len; const u_char *p; /* sanity check */ if (!ip) return -1; if (ns) ns->ip_ver = ip->ip_v; if (ip->ip_v == 4) { struct ip_address *src = 0, *dst = 0; if (ns) { src = &ns->ip_src_addr; dst = &ns->ip_dst_addr; ns->ip_proto = ip->ip_p; src->ip_addr = ip->ip_src; dst->ip_addr = ip->ip_dst; ns->pkt_len = ntohs(ip->ip_len); } hdrlen = ip->ip_hl << 2; caplen -= hdrlen; if ((ntohs(ip->ip_off) & 0x1fff) == 0) { p = (const u_char *)ip + hdrlen; switch (ip->ip_p) { case IPPROTO_TCP: #if defined(linux) len = ((const struct tcphdr *)p)->doff << 2; #else len = ((const struct tcphdr *)p)->th_off << 2; #endif hdrlen += len; caplen -= len; if (caplen >= 0 && src && dst) { #if defined(linux) src->ip_port = ((const struct tcphdr *)p)->source; dst->ip_port = ((const struct tcphdr *)p)->dest; #else src->ip_port = ((const struct tcphdr *)p)->th_sport; dst->ip_port = ((const struct tcphdr *)p)->th_dport; #endif } break; case IPPROTO_UDP: len = sizeof(struct udphdr); hdrlen += len; caplen -= len; if (caplen >= 0 && src && dst) { #if defined(linux) src->ip_port = ((const struct udphdr *)p)->source; dst->ip_port = ((const struct udphdr *)p)->dest; #else src->ip_port = ((const struct udphdr *)p)->uh_sport; dst->ip_port = ((const struct udphdr *)p)->uh_dport; #endif } break; case IPPROTO_ICMP: len = (u_char *)((const struct icmp *)p)->icmp_data - p; hdrlen += len; caplen -= len; if (caplen >= 0 && src) { src->ip_port = ((((const struct icmp *)p)->icmp_type << 8) | ((const struct icmp *)p)->icmp_code) + 1; } break; } } } #ifdef INET6 else if (ip->ip_v == 6) { struct ip6_hdr *ip6 = (struct ip6_hdr *)ip; struct ip_address *src = 0, *dst = 0; if (ns) { src = &ns->ip_src_addr; dst = &ns->ip_dst_addr; ns->ip_proto = ip6->ip6_nxt; src->ip6_addr = ip6->ip6_src; dst->ip6_addr = ip6->ip6_dst; ns->pkt_len = sizeof(struct ip6_hdr) + ntohs(ip6->ip6_plen); } hdrlen = sizeof(struct ip6_hdr); caplen -= hdrlen; p = (const u_char *)ip6 + hdrlen; switch (ip6->ip6_nxt) { case IPPROTO_TCP: #if defined(linux) len = ((const struct tcphdr *)p)->doff << 2; #else len = ((const struct tcphdr *)p)->th_off << 2; #endif hdrlen += len; caplen -= len; if (caplen >= 0 && src && dst) { #if defined(linux) src->ip_port = ((const struct tcphdr *)p)->source; dst->ip_port = ((const struct tcphdr *)p)->dest; #else src->ip_port = ((const struct tcphdr *)p)->th_sport; dst->ip_port = ((const struct tcphdr *)p)->th_dport; #endif } break; case IPPROTO_UDP: len = sizeof(struct udphdr); hdrlen += len; caplen -= len; if (caplen >= 0 && src && dst) { #if defined(linux) src->ip_port = ((const struct udphdr *)p)->source; dst->ip_port = ((const struct udphdr *)p)->dest; #else src->ip_port = ((const struct udphdr *)p)->uh_sport; dst->ip_port = ((const struct udphdr *)p)->uh_dport; #endif } break; case IPPROTO_ICMPV6: len = sizeof(struct icmp6_hdr); hdrlen += len; caplen -= len; if (caplen >= 0 && src) { src->ip_port = ((((const struct icmp6_hdr *)p)->icmp6_type << 8) | ((const struct icmp6_hdr *)p)->icmp6_code) + 1; } break; } } #endif else { /* unknown IP version */ return -1; } if (ns) { ns->pkt_cnt = 1; if (ns->pkt_len >= hdrlen) ns->data_len = ns->pkt_len - hdrlen; } return hdrlen; }