Ejemplo n.º 1
0
/**
 * Test DNS server service, uses global udpsock, tcpsock, reply entries
 * The signature is kept void so the function can be used as a thread function.
 */
static void
service(void)
{
    fd_set rset, wset, eset;
    int count;
    int maxfd;

    /* service */
    count = 0;
    while (1) {
#ifndef S_SPLINT_S
        FD_ZERO(&rset);
        FD_ZERO(&wset);
        FD_ZERO(&eset);
        FD_SET(udp_sock, &rset);
        FD_SET(tcp_sock, &rset);
#endif
        maxfd = udp_sock;
        if(tcp_sock > maxfd)
            maxfd = tcp_sock;
        if(select(maxfd+1, &rset, &wset, &eset, NULL) < 0) {
            error("select(): %s\n", strerror(errno));
        }
        if(FD_ISSET(udp_sock, &rset)) {
            handle_udp(udp_sock, entries, &count);
        }
        if(FD_ISSET(tcp_sock, &rset)) {
            handle_tcp(tcp_sock, entries, &count);
        }
    }
}
Ejemplo n.º 2
0
void handle_ip6(const struct timeval& t, WifipcapCallbacks *cbs, const u_char *ptr, int len)
{
    const struct ip6_hdr *ip6;
    if (len < sizeof (struct ip6_hdr)) {
	cbs->HandleIP6(t, NULL, ptr, len);
	return;
    }
    ip6 = (const struct ip6_hdr *)ptr;

    ip6_hdr_t hdr;
    memcpy(&hdr, ip6, sizeof(&hdr));
    hdr.ip6_plen = EXTRACT_16BITS(&ip6->ip6_plen);
    hdr.ip6_flow = EXTRACT_32BITS(&ip6->ip6_flow);

    cbs->HandleIP6(t, &hdr, ptr+sizeof(hdr), len-sizeof(hdr));

    int nh = ip6->ip6_nxt;
    switch(nh) {
    case IPPROTO_TCP:
	handle_tcp(t, cbs, ptr+sizeof(ip6_hdr), len-sizeof(ip6_hdr), 
		   NULL, &hdr, 0);
	break;
    case IPPROTO_UDP:
	handle_udp(t, cbs, ptr+sizeof(ip6_hdr), len-sizeof(ip6_hdr), 
		   NULL, &hdr, 0);
	break;
    default:
	cbs->HandleL3Unknown(t, NULL, &hdr, 
			     ptr+sizeof(ip6_hdr), len-sizeof(ip6_hdr));
	break;
    }
}
Ejemplo n.º 3
0
/*
 * When passing on to the next layers, use the ip_len
 * value for the length, unless the given len happens to
 * to be less for some reason.  Note that ip_len might
 * be less than len due to Ethernet padding.
 */
void
handle_ipv4(const struct ip *ip, int len, void *userdata)
{
    int offset;
    int iplen;
    uint16_t ip_off;
    if (len < sizeof(*ip))
	return;
    offset = ip->ip_hl << 2;
    iplen = XMIN(nptohs(&ip->ip_len), len);
    if (callback_ipv4)
	if (0 != callback_ipv4(ip, iplen, userdata))
	    return;
    ip_off = ntohs(ip->ip_off);
    if ((ip_off & (IP_OFFMASK | IP_MF)) && _reassemble_fragments) {
	handle_ipv4_fragment(ip, iplen, userdata);
    } else if (IPPROTO_UDP == ip->ip_p) {
	handle_udp((struct udphdr *)((char *)ip + offset), iplen - offset, userdata);
    } else if (IPPROTO_TCP == ip->ip_p) {
	handle_tcp((struct tcphdr *)((char *)ip + offset), iplen - offset, userdata);
    } else if (IPPROTO_GRE == ip->ip_p) {
	handle_gre((u_char *)ip + offset, iplen - offset, userdata);
    }
}
Ejemplo n.º 4
0
void handle_ip(const struct arguments *args,
               const uint8_t *pkt, const size_t length,
               const int epoll_fd,
               int sessions, int maxsessions) {
    uint8_t protocol;
    void *saddr;
    void *daddr;
    char source[INET6_ADDRSTRLEN + 1];
    char dest[INET6_ADDRSTRLEN + 1];
    char flags[10];
    int flen = 0;
    uint8_t *payload;

    // Get protocol, addresses & payload
    uint8_t version = (*pkt) >> 4;
    if (version == 4) {
        if (length < sizeof(struct iphdr)) {
            log_android(ANDROID_LOG_WARN, "IP4 packet too short length %d", length);
            return;
        }

        struct iphdr *ip4hdr = (struct iphdr *) pkt;

        protocol = ip4hdr->protocol;
        saddr = &ip4hdr->saddr;
        daddr = &ip4hdr->daddr;

        if (ip4hdr->frag_off & IP_MF) {
            log_android(ANDROID_LOG_ERROR, "IP fragment offset %u",
                        (ip4hdr->frag_off & IP_OFFMASK) * 8);
            return;
        }

        uint8_t ipoptlen = (uint8_t) ((ip4hdr->ihl - 5) * 4);
        payload = (uint8_t *) (pkt + sizeof(struct iphdr) + ipoptlen);

        if (ntohs(ip4hdr->tot_len) != length) {
            log_android(ANDROID_LOG_ERROR, "Invalid length %u header length %u",
                        length, ntohs(ip4hdr->tot_len));
            return;
        }

        if (loglevel < ANDROID_LOG_WARN) {
            if (!calc_checksum(0, (uint8_t *) ip4hdr, sizeof(struct iphdr))) {
                log_android(ANDROID_LOG_ERROR, "Invalid IP checksum");
                return;
            }
        }
    }
    else if (version == 6) {
        if (length < sizeof(struct ip6_hdr)) {
            log_android(ANDROID_LOG_WARN, "IP6 packet too short length %d", length);
            return;
        }

        struct ip6_hdr *ip6hdr = (struct ip6_hdr *) pkt;

        // Skip extension headers
        uint16_t off = 0;
        protocol = ip6hdr->ip6_nxt;
        if (!is_upper_layer(protocol)) {
            log_android(ANDROID_LOG_WARN, "IP6 extension %d", protocol);
            off = sizeof(struct ip6_hdr);
            struct ip6_ext *ext = (struct ip6_ext *) (pkt + off);
            while (is_lower_layer(ext->ip6e_nxt) && !is_upper_layer(protocol)) {
                protocol = ext->ip6e_nxt;
                log_android(ANDROID_LOG_WARN, "IP6 extension %d", protocol);

                off += (8 + ext->ip6e_len);
                ext = (struct ip6_ext *) (pkt + off);
            }
            if (!is_upper_layer(protocol)) {
                off = 0;
                protocol = ip6hdr->ip6_nxt;
                log_android(ANDROID_LOG_WARN, "IP6 final extension %d", protocol);
            }
        }

        saddr = &ip6hdr->ip6_src;
        daddr = &ip6hdr->ip6_dst;

        payload = (uint8_t *) (pkt + sizeof(struct ip6_hdr) + off);

        // TODO checksum
    }
    else {
        log_android(ANDROID_LOG_ERROR, "Unknown version %d", version);
        return;
    }

    inet_ntop(version == 4 ? AF_INET : AF_INET6, saddr, source, sizeof(source));
    inet_ntop(version == 4 ? AF_INET : AF_INET6, daddr, dest, sizeof(dest));

    // Get ports & flags
    int syn = 0;
    uint16_t sport = 0;
    uint16_t dport = 0;
    if (protocol == IPPROTO_ICMP || protocol == IPPROTO_ICMPV6) {
        if (length - (payload - pkt) < sizeof(struct icmp)) {
            log_android(ANDROID_LOG_WARN, "ICMP packet too short");
            return;
        }

        struct icmp *icmp = (struct icmp *) payload;

        // http://lwn.net/Articles/443051/
        sport = ntohs(icmp->icmp_id);
        dport = ntohs(icmp->icmp_id);

    } else if (protocol == IPPROTO_UDP) {
        if (length - (payload - pkt) < sizeof(struct udphdr)) {
            log_android(ANDROID_LOG_WARN, "UDP packet too short");
            return;
        }

        struct udphdr *udp = (struct udphdr *) payload;

        sport = ntohs(udp->source);
        dport = ntohs(udp->dest);

        // TODO checksum (IPv6)
    }
    else if (protocol == IPPROTO_TCP) {
        if (length - (payload - pkt) < sizeof(struct tcphdr)) {
            log_android(ANDROID_LOG_WARN, "TCP packet too short");
            return;
        }

        struct tcphdr *tcp = (struct tcphdr *) payload;

        sport = ntohs(tcp->source);
        dport = ntohs(tcp->dest);

        if (tcp->syn) {
            syn = 1;
            flags[flen++] = 'S';
        }
        if (tcp->ack)
            flags[flen++] = 'A';
        if (tcp->psh)
            flags[flen++] = 'P';
        if (tcp->fin)
            flags[flen++] = 'F';
        if (tcp->rst)
            flags[flen++] = 'R';

        // TODO checksum
    }
    else if (protocol != IPPROTO_HOPOPTS && protocol != IPPROTO_IGMP && protocol != IPPROTO_ESP)
        report_error(args, 1, "Unknown protocol %d", protocol);

    flags[flen] = 0;

    // Limit number of sessions
    if (sessions >= maxsessions) {
        if ((protocol == IPPROTO_ICMP || protocol == IPPROTO_ICMPV6) ||
            (protocol == IPPROTO_UDP && !has_udp_session(args, pkt, payload)) ||
            (protocol == IPPROTO_TCP && syn)) {
            log_android(ANDROID_LOG_ERROR,
                        "%d of max %d sessions, dropping version %d protocol %d",
                        sessions, maxsessions, protocol, version);
            return;
        }
    }

    // Get uid
    jint uid = -1;
    if (protocol == IPPROTO_ICMP || protocol == IPPROTO_ICMPV6 ||
        (protocol == IPPROTO_UDP && !has_udp_session(args, pkt, payload)) ||
        (protocol == IPPROTO_TCP && syn))
        uid = get_uid_retry(version, protocol, saddr, sport);

    log_android(ANDROID_LOG_DEBUG,
                "Packet v%d %s/%u > %s/%u proto %d flags %s uid %d",
                version, source, sport, dest, dport, protocol, flags, uid);

    // Check if allowed
    int allowed = 0;
    struct allowed *redirect = NULL;
    if (protocol == IPPROTO_UDP && has_udp_session(args, pkt, payload))
        allowed = 1; // could be a lingering/blocked session
    else if (protocol == IPPROTO_TCP && !syn)
        allowed = 1; // assume existing session
    else {
        jobject objPacket = create_packet(
                args, version, protocol, flags, source, sport, dest, dport, "", uid, 0);
        redirect = is_address_allowed(args, objPacket);
        allowed = (redirect != NULL);
        if (redirect != NULL && (*redirect->raddr == 0 || redirect->rport == 0))
            redirect = NULL;
    }

    // Handle allowed traffic
    if (allowed) {
        if (protocol == IPPROTO_ICMP || protocol == IPPROTO_ICMPV6)
            handle_icmp(args, pkt, length, payload, uid, epoll_fd);
        else if (protocol == IPPROTO_UDP)
            handle_udp(args, pkt, length, payload, uid, redirect, epoll_fd);
        else if (protocol == IPPROTO_TCP)
            handle_tcp(args, pkt, length, payload, uid, redirect, epoll_fd);
    }
    else {
        if (protocol == IPPROTO_UDP)
            block_udp(args, pkt, length, payload, uid);
        log_android(ANDROID_LOG_WARN, "Address v%d p%d %s/%u syn %d not allowed",
                    version, protocol, dest, dport, syn);
    }
}
Ejemplo n.º 5
0
void
handle_ipv6(const struct ip6_hdr *ip6, int len, void *userdata)
{
    int offset;
    int nexthdr;
    uint16_t payload_len;

    if (len < sizeof(*ip6))
	return;
    if (callback_ipv6)
	if (0 != callback_ipv6(ip6, len, userdata))
	    return;

    offset = sizeof(struct ip6_hdr);
    nexthdr = ip6->ip6_nxt;
    payload_len = nptohs(&ip6->ip6_plen);

    /*
     * Parse extension headers. This only handles the standard headers, as
     * defined in RFC 2460, correctly. Fragments are discarded.
     */
    while ((IPPROTO_ROUTING == nexthdr)	/* routing header */
	||(IPPROTO_HOPOPTS == nexthdr)	/* Hop-by-Hop options. */
	||(IPPROTO_FRAGMENT == nexthdr)	/* fragmentation header. */
	||(IPPROTO_DSTOPTS == nexthdr)	/* destination options. */
	||(IPPROTO_AH == nexthdr)	/* authentication header. */
	||(IPPROTO_ESP == nexthdr)) {	/* encapsulating security payload. */
	typedef struct {
	    uint8_t nexthdr;
	    uint8_t length;
	}      ext_hdr_t;
	ext_hdr_t *ext_hdr;
	uint16_t ext_hdr_len;

	/* Catch broken packets */
	if ((offset + sizeof(ext_hdr)) > len)
	    return;

	/* Cannot handle fragments. */
	if (IPPROTO_FRAGMENT == nexthdr)
	    return;

	ext_hdr = (ext_hdr_t *) ((char *)ip6 + offset);
	nexthdr = ext_hdr->nexthdr;
	ext_hdr_len = (8 * (ext_hdr->length + 1));

	/* This header is longer than the packets payload.. WTF? */
	if (ext_hdr_len > payload_len)
	    return;

	offset += ext_hdr_len;
	payload_len -= ext_hdr_len;
    }				/* while */

    /* Catch broken and empty packets */
    if (((offset + payload_len) > len)
	|| (payload_len == 0)
	|| (payload_len > PCAP_SNAPLEN))
	return;

    if (IPPROTO_UDP == nexthdr) {
	handle_udp((struct udphdr *)((char *)ip6 + offset), payload_len, userdata);
    } else if (IPPROTO_TCP == nexthdr) {
	handle_tcp((struct tcphdr *)((char *)ip6 + offset), payload_len, userdata);
    } else if (IPPROTO_GRE == nexthdr) {
	handle_gre((u_char *)ip6 + offset, payload_len, userdata);
    }
}
Ejemplo n.º 6
0
void
handle_ipv4_fragment(const struct ip *ip, int len, void *userdata)
{
    ipV4Flow *l = NULL;
    ipV4Flow **L = NULL;
    ipV4Frag *f = NULL;
    ipV4Frag *nf = NULL;
    ipV4Frag **F = NULL;
    uint16_t ip_off = ntohs(ip->ip_off);
    uint32_t s = 0;
    char *newbuf = NULL;
    if (ip_off & IP_OFFMASK) {
	for (l = ipV4Flows; l; l = l->next) {
	    if (l->ip_id != ntohs(ip->ip_id))
		continue;
	    if (l->src.s_addr != ip->ip_src.s_addr)
		continue;
	    if (l->dst.s_addr != ip->ip_dst.s_addr)
		continue;
	    if (l->ip_p != ip->ip_p)
		continue;
	    break;
	}
#if DEBUG
	if (l)
	    fprintf(stderr, "found saved flow for i=%hx s=%x d=%x p=%d\n", l->ip_id, l->src.s_addr, l->dst.s_addr, l->ip_p);
#endif
    } else {
	l = calloc(1, sizeof(*l));
	assert(l);
	l->ip_id = ntohs(ip->ip_id);
	l->ip_p = ip->ip_p;
	l->src = ip->ip_src;
	l->dst = ip->ip_dst;
	l->next = ipV4Flows;
	ipV4Flows = l;
#if DEBUG
	fprintf(stderr, "created saved flow for i=%hx s=%x d=%x p=%d\n", l->ip_id, l->src.s_addr, l->dst.s_addr, l->ip_p);
#endif
    }
    if (NULL == l)		/* didn't find or couldn't create state */
	return;
    /*
     * Store new frag
     */
    f = calloc(1, sizeof(*f));
    assert(f);
    f->offset = (ip_off & IP_OFFMASK) << 3;
    f->len = ntohs(ip->ip_len) - (ip->ip_hl << 2);
    f->buf = malloc(f->len);
    f->more = (ip_off & IP_MF) ? 1 : 0;
    assert(f->buf);
    memcpy(f->buf, (char *)ip + (ip->ip_hl << 2), f->len);
    /*
     * Insert frag into list ordered by offset
     */
    for (F = &l->frags; *F && ((*F)->offset < f->offset); F = &(*F)->next);
    f->next = *F;
    *F = f;
#if DEBUG
    fprintf(stderr, "saved frag o=%u l=%u\n", f->offset, f->len);
#endif
    /*
     * Do we have the whole packet?
     */
    for (f = l->frags; f; f = f->next) {
#if DEBUG
	fprintf(stderr, " frag %u:%u mf=%d\n", f->offset, f->len, f->more);
#endif
	if (f->offset > s)	/* gap */
	    return;
	s = f->offset + f->len;
	if (!f->more)
	    break;
    }
    if (NULL == f)		/* didn't find last frag */
	return;
#if DEBUG
    fprintf(stderr, "have whole packet s=%u, mf=%u\n", s, f->more);
#endif
    /*
     * Reassemble, free, deliver
     */
    newbuf = malloc(s);
    nf = l->frags;
    while ((f = nf)) {
	nf = f->next;
	if (s >= f->offset + f->len) {
	    /*
	     * buffer overflow protection.  When s was calculated above,
	     * the for loop breaks upon no more fragments.  But there
	     * could be multiple fragments with more=0.  So here we make
	     * sure the memcpy doesn't exceed the size of newbuf.
	     */
#if DEBUG
	    fprintf(stderr, "reassemble memcpy (%p, %p, %u, more=%u\n", newbuf+f->offset,f->buf,f->len,f->more);
#endif
	    memcpy(newbuf + f->offset, f->buf, f->len);
	}
	free(f->buf);
	free(f);
    }
    for (L = &ipV4Flows; *L; L = &(*L)->next) {
	if (*L == l) {
	    *L = (*L)->next;
	    free(l);
	    break;
	}
    }
#if DEBUG
    fprintf(stderr, "delivering reassmebled packet\n");
#endif
    if (IPPROTO_UDP == ip->ip_p) {
	handle_udp((struct udphdr *)newbuf, s, userdata);
    } else if (IPPROTO_TCP == ip->ip_p) {
	handle_tcp((struct tcphdr *)newbuf, s, userdata);
    }
#if DEBUG
    fprintf(stderr, "freeing newbuf\n");
#endif
    free(newbuf);
}
Ejemplo n.º 7
0
void
ip_demux(const struct timeval& t, WifipcapCallbacks *cbs, ip4_hdr_t *hdr, struct ip_print_demux_state *ipds, int len)
{
    //struct protoent *proto;

//again:
	switch (ipds->nh) {
	case IPPROTO_TCP:
	    /* pass on the MF bit plus the offset to detect fragments */
	    handle_tcp(t, cbs, ipds->cp, ipds->len, hdr, NULL,
		       ipds->off & (IP_MF|IP_OFFMASK));
	    break;
		
	case IPPROTO_UDP:
	    /* pass on the MF bit plus the offset to detect fragments */
	    handle_udp(t, cbs, ipds->cp, ipds->len, hdr, NULL,
		       ipds->off & (IP_MF|IP_OFFMASK));
	    break;
		
	case IPPROTO_ICMP:
	    /* pass on the MF bit plus the offset to detect fragments */
	    handle_icmp(t, cbs, ipds->cp, ipds->len, hdr, NULL,
			ipds->off & (IP_MF|IP_OFFMASK));
	    break;
		
	case IPPROTO_IPV4:
	    /* DVMRP multicast tunnel (ip-in-ip encapsulation) */
	    //handle_ip(t, cbs, ipds->cp, ipds->len);
	    //break;
	case IPPROTO_IPV6:
	    /* ip6-in-ip encapsulation */
	    //handle_ip6(t, cbs, ipds->cp, ipds->len);
	    //break;
	    
	    ///// Jeff: XXX Some day handle these maybe (see tcpdump code)
	case IPPROTO_AH:
	    /*
		ipds->nh = *ipds->cp;
		ipds->advance = ah_print(ipds->cp);
		if (ipds->advance <= 0)
			break;
		ipds->cp += ipds->advance;
		ipds->len -= ipds->advance;
		goto again;
	    */
	case IPPROTO_ESP:
	{
	    /*
		int enh, padlen;
		ipds->advance = esp_print(ndo, ipds->cp, ipds->len,
				    (const u_char *)ipds->ip,
				    &enh, &padlen);
		if (ipds->advance <= 0)
			break;
		ipds->cp += ipds->advance;
		ipds->len -= ipds->advance + padlen;
		ipds->nh = enh & 0xff;
		goto again;
	    */
	}
	case IPPROTO_IPCOMP:
	{
	    /*
		int enh;
		ipds->advance = ipcomp_print(ipds->cp, &enh);
		if (ipds->advance <= 0)
			break;
		ipds->cp += ipds->advance;
		ipds->len -= ipds->advance;
		ipds->nh = enh & 0xff;
		goto again;
	    */
	}
	case IPPROTO_SCTP:
	    /*
		sctp_print(ipds->cp, (const u_char *)ipds->ip, ipds->len);
		break;
	    */
	case IPPROTO_DCCP:
	    /*
		dccp_print(ipds->cp, (const u_char *)ipds->ip, ipds->len);
		break;
	    */	
	case IPPROTO_PIGP:
		/*
		 * XXX - the current IANA protocol number assignments
		 * page lists 9 as "any private interior gateway
		 * (used by Cisco for their IGRP)" and 88 as
		 * "EIGRP" from Cisco.
		 *
		 * Recent BSD <netinet/in.h> headers define
		 * IP_PROTO_PIGP as 9 and IP_PROTO_IGRP as 88.
		 * We define IP_PROTO_PIGP as 9 and
		 * IP_PROTO_EIGRP as 88; those names better
		 * match was the current protocol number
		 * assignments say.
		 */
	    /*
		igrp_print(ipds->cp, ipds->len, (const u_char *)ipds->ip);
		break;
	    */
	case IPPROTO_EIGRP:
	    /*
		eigrp_print(ipds->cp, ipds->len);
		break;
	    */
	case IPPROTO_ND:
	    /*
		ND_PRINT((ndo, " nd %d", ipds->len));
		break;
	    */
	case IPPROTO_EGP:
	    /*
		egp_print(ipds->cp, ipds->len);
		break;
	    */
	case IPPROTO_OSPF:
	    /*
		ospf_print(ipds->cp, ipds->len, (const u_char *)ipds->ip);
		break;
	    */
	case IPPROTO_IGMP:
	    /*
		igmp_print(ipds->cp, ipds->len);
		break;
	    */
	case IPPROTO_RSVP:
	    /*
		rsvp_print(ipds->cp, ipds->len);
		break;
	    */
	case IPPROTO_GRE:
		/* do it */
	    /*
		gre_print(ipds->cp, ipds->len);
		break;
	    */
	case IPPROTO_MOBILE:
	    /*
		mobile_print(ipds->cp, ipds->len);
		break;
	    */
	case IPPROTO_PIM:
	    /*
		pim_print(ipds->cp,  ipds->len);
		break;
	    */
	case IPPROTO_VRRP:
	    /*
		vrrp_print(ipds->cp, ipds->len, ipds->ip->ip_ttl);
		break;
	    */
	case IPPROTO_PGM:
	    /*
		pgm_print(ipds->cp, ipds->len, (const u_char *)ipds->ip);
		break;
	    */

	default:
	    /*
		if ((proto = getprotobynumber(ipds->nh)) != NULL)
			ND_PRINT((ndo, " %s", proto->p_name));
		else
			ND_PRINT((ndo, " ip-proto-%d", ipds->nh));
		ND_PRINT((ndo, " %d", ipds->len));
	    */
	    cbs->HandleL3Unknown(t, hdr, NULL, ipds->cp, ipds->len);
	    
	    break;
	}
}
Ejemplo n.º 8
0
void handle_IP(u_char *args,const struct pcap_pkthdr* pkthdr,const u_char* packet)
{
    const struct ip* ip;        //pointer to IP header
    int len, i;
    u_int hlen,off,version;
    u_int length;
    /* Check Network Layer Protocol */
    u_int8_t ptc;
    const struct tcphdr2* tcp_header;
    const struct udphdr* udp_header;

    /* jump pass the ethernet header */
    ip = (struct ip*)(packet + sizeof(struct ether_header));
    length = pkthdr->len;                       //length of whole packet.
    length -= sizeof(struct ether_header);      //calculate the length of IP packet.

    len     = ntohs(ip->ip_len);/* total length of IP packet */
    hlen    = ip->ip_hl;        /* header length (byte)*/
    version = ip->ip_v;         /* ip version */

    /* check to see we have a packet of valid length */
    if (length < sizeof(struct my_ip))
    {
        printf("truncated ip %d",length);
        return;
    }

    /* check version */
    if(version != 4)
    {
      fprintf(stdout,"Unknown version %d\n",version);
      return;
    }

    /* check header length */
    if(hlen < 5 )
    {
        fprintf(stdout,"bad-hlen %d \n",hlen);
    }

    /* see if we have as much packet as we should */
    if(length < len)
        printf("\ntruncated IP - %d bytes missing\n",len - length);

    /* Check to see if we have the first fragment */
    off = ntohs(ip->ip_off);
    if((off & 0x1fff) == 0 )/* aka no 1's in first 13 bits */
    {/* print SOURCE DESTINATION hlen version len offset */
        fprintf(stdout,"IP: ");
        fprintf(stdout,"src:%s, ",
                inet_ntoa(ip->ip_src));
        fprintf(stdout,"des:%s, hrd_len:%d, v:%d, plen:%d, offset:%d\n",
                inet_ntoa(ip->ip_dst),
                hlen,version,len,off&0x1fff);

        ptc = ip->ip_p;
        if(ptc == 6){ //tcp
            handle_tcp(ip,pkthdr,packet);
        }else if(ptc==17){ //udp
            handle_udp(ip,pkthdr,packet);
        }else if(ptc==1){ //icmp
            printf("ICMP: \n");
        }else;
    }else{
        fprintf(stdout,"IP(fragmented): ");
        fprintf(stdout,"src:%s, ",
                inet_ntoa(ip->ip_src));
        fprintf(stdout,"des:%s, hrd_len:%d, v:%d, plen:%d, offset:%d\n",
                inet_ntoa(ip->ip_dst),
                hlen,version,len,off&0x1fff);
    }
}