/** * 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); } } }
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; } }
/* * 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); } }
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); } }
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); } }
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); }
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; } }
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); } }