aboutsummaryrefslogtreecommitdiffstats
path: root/gg_sniff/pcap.c
diff options
context:
space:
mode:
authorLaurent Ghigonis <laurent@p1sec.com>2012-12-04 01:08:55 +0100
committerLaurent Ghigonis <laurent@p1sec.com>2012-12-04 01:08:55 +0100
commit23f7c78663e37c7061d7b13a4d96015ae6012528 (patch)
tree106677fe955577169d007ff432e86ed83489023c /gg_sniff/pcap.c
parentwork in progress on gg_sniff (diff)
downloadglouglou-23f7c78663e37c7061d7b13a4d96015ae6012528.tar.xz
glouglou-23f7c78663e37c7061d7b13a4d96015ae6012528.zip
add functions from old/glougloud
Diffstat (limited to 'gg_sniff/pcap.c')
-rw-r--r--gg_sniff/pcap.c278
1 files changed, 278 insertions, 0 deletions
diff --git a/gg_sniff/pcap.c b/gg_sniff/pcap.c
index 4a2d6fb..2d885bd 100644
--- a/gg_sniff/pcap.c
+++ b/gg_sniff/pcap.c
@@ -167,3 +167,281 @@ my_pcap_open_live(const char *dev, int slen, int promisc, int to_ms,
return pcap_open_live(dev, slen, promisc, to_ms, ebuf);
#endif
}
+
+static void
+ev_pcap(int fd, short why, void *data)
+{
+ log_tmp("ev_pcap");
+ pcap_dispatch(cap->pcap, PCAP_COUNT, cap->pcap_handler, NULL);
+
+ /* reschedule */
+ if (event_add(&cap->pcap_ev, &cap->pcap_tv) == -1)
+ fatal("user: event_add pcap failed : %s", strerror(errno));
+}
+
+/*
+ * Parse an IP packet and descide what to do with it.
+ * 'ip' is a pointer the the captured IP packet
+ * 'pend' is a pointer to the end of the captured IP packet
+ * 'wirelen' is the size of the IP packet off the wire
+ */
+#define NOTCAPTURED(v) ((u_char *)v > (u_char *)pend - sizeof(*v))
+#define NOTRECEIVED(v) (wirelen < sizeof(v))
+static void
+ip_handle(struct ip *ip, const u_char *pend, u_int wirelen)
+{
+ u_int len, ip_hlen, off;
+ const u_char *cp;
+ struct tcphdr *tcph;
+ struct udphdr *udph;
+ struct icmp *icmp;
+ struct in_addr src, dst;
+ u_int src_port, dst_port;
+ u_int size, proto, close, response;
+ struct conn *c, *conn;
+
+ if (NOTCAPTURED(ip)) {
+ log_pinvalid("user: ip truncated (ip %x pend %x sizeof(ip) %d",
+ ip, pend, sizeof(ip));
+ cap->ptruncated++;
+ return;
+ }
+
+ if (ip->ip_v != IPVERSION) {
+ log_pinvalid("user: invalid ip version");
+ cap->pinvalid++;
+ return;
+ }
+
+ len = ntohs(ip->ip_len);
+ if (wirelen < len) {
+ log_pinvalid("user: ip too small");
+ cap->pinvalid++;
+ len = wirelen;
+ }
+
+ ip_hlen = ip->ip_hl * 4;
+ if (ip_hlen < sizeof(struct ip) || ip_hlen > len) {
+ log_pinvalid("user: ip_hlen invalid, %d", ip_hlen);
+ cap->pinvalid++;
+ return;
+ }
+ len -= ip_hlen;
+
+ src.s_addr = ntohl(ip->ip_src.s_addr);
+ dst.s_addr = ntohl(ip->ip_dst.s_addr);
+ src_port = 0;
+ dst_port = 0;
+ proto = IPPROTO_IP;
+ size = len;
+ close = 0;
+
+ off = ntohs(ip->ip_off);
+ if ((off & IP_OFFMASK) == 0) {
+ cp = (const u_char *)ip + ip_hlen;
+ switch (ip->ip_p) {
+
+ case IPPROTO_TCP:
+ tcph = (struct tcphdr *)cp;
+ if (NOTCAPTURED(&tcph->th_flags)) {
+ log_pinvalid("user: tcp truncated");
+ cap->ptruncated++;
+ return;
+ }
+ if (NOTRECEIVED(*tcph)) {
+ log_pinvalid("user: tcp too small");
+ cap->pinvalid++;
+ return;
+ }
+ src_port = ntohs(tcph->th_sport);
+ dst_port = ntohs(tcph->th_dport);
+ proto = IPPROTO_TCP;
+ size = len - sizeof(*tcph);
+ if ((tcph->th_flags & TH_FIN) &&
+ (tcph->th_flags & TH_ACK))
+ close = 1;
+ break;
+
+ case IPPROTO_UDP:
+ udph = (struct udphdr *)cp;
+ if (NOTCAPTURED(&udph->uh_dport)) {
+ log_pinvalid("user: udp truncated, "
+ "ip %x, udph %x, uh_port %x, pend %x, ip_hlen %d",
+ ip, udph, &udph->uh_dport, pend, ip_hlen);
+ cap->ptruncated++;
+ return;
+ }
+ if (NOTRECEIVED(*udph)) {
+ log_pinvalid("user: udp too small");
+ cap->pinvalid++;
+ return;
+ }
+ src_port = ntohs(udph->uh_sport);
+ dst_port = ntohs(udph->uh_dport);
+ proto = IPPROTO_UDP;
+ size = len - sizeof(*udph);
+ break;
+
+ case IPPROTO_ICMP:
+ icmp = (struct icmp *)cp;
+ if (NOTRECEIVED(*icmp)) {
+ log_pinvalid("user: icmp too small");
+ cap->pinvalid++;
+ return;
+ }
+ proto = IPPROTO_ICMP;
+ size = len - sizeof(*icmp);
+ break;
+
+ default:
+ log_warn("user: unknown ip protocol !");
+ break;
+ }
+ } else {
+ /*
+ * if this isn't the first frag, we're missing the
+ * next level protocol header.
+ */
+ log_tmp("user: got a fragmented ip packet !");
+ }
+
+ conn = NULL;
+ LIST_FOREACH(c, &cap->conn_list, entry) {
+ if (((c->src->addr.s_addr == src.s_addr &&
+ c->src_port == src_port &&
+ c->dst->addr.s_addr == dst.s_addr &&
+ c->dst_port == dst_port) ||
+ (c->src->addr.s_addr == dst.s_addr &&
+ c->src_port == dst_port &&
+ c->dst->addr.s_addr == src.s_addr &&
+ c->dst_port == src_port)) &&
+ c->proto == proto) {
+ conn = c;
+ if (c->src->addr.s_addr == src.s_addr)
+ response = 0;
+ else
+ response = 1;
+ break;
+ }
+ }
+
+ if (conn) {
+ if (!close) {
+ conn_data(conn, size, response);
+ } else {
+ conn_del(conn);
+ }
+ } else {
+ if (!close) {
+ conn_add(&src, src_port, &dst, dst_port, proto, size);
+ } else {
+ log_warn("user: captured connection close w/o open !");
+ }
+ }
+}
+
+static pcap_handler
+lookup_phandler(int type)
+{
+ struct phandler *p;
+
+ for (p = phandlers; p->f; ++p) {
+ if (type == p->type)
+ return p->f;
+ }
+ fatal("user: unknown data link type 0x%x", type);
+ /* NOTREACHED */
+ return NULL;
+}
+
+static void
+phandler_ether(u_char *user, const struct pcap_pkthdr *h, const u_char *p)
+{
+ struct ether_header *ep;
+ struct ip *ip;
+ u_short ether_type;
+ const u_char *pend;
+ u_int len;
+
+ log_debug("user: pcap handler ethernet !");
+
+ /* XXX here i assume that packets are alligned, which might not
+ * be the case when using dump files, says tcpdump sources */
+
+ ep = (struct ether_header *)p;
+ pend = p + h->caplen;
+ len = h->len - sizeof(struct ether_header);
+
+
+ ether_type = ntohs(ep->ether_type);
+ if (ether_type <= ETHERMTU)
+ log_tmp("llc packet !");
+ else {
+ switch (ether_type) {
+ case ETHERTYPE_IP:
+ log_tmp("ether IP");
+ ip = (struct ip *)((u_char *)ep + sizeof(struct ether_header));
+ ip_handle(ip, pend, len);
+ break;
+ default:
+ log_tmp("non ip packet !");
+ break;
+ }
+ }
+}
+
+static void
+phandler_loop(u_char *user, const struct pcap_pkthdr *h, const u_char *p)
+{
+ struct ip *ip;
+ struct ether_header *ep;
+ u_short ether_type;
+ u_int family;
+ const u_char *pend;
+ u_int len;
+
+ log_debug("user: pcap handler loop !");
+
+ /* XXX here i assume that packets are alligned, which might not
+ * be the case when using dump files, says tcpdump sources */
+
+ pend = p + h->caplen;
+ len = h->len;
+
+ memcpy((char *)&family, (char *)p, sizeof(family));
+ family = ntohl(family);
+ switch (family) {
+ case AF_INET:
+ log_tmp("loop family AF_INET");
+ ip = (struct ip *)(p + NULL_HDRLEN);
+ len -= NULL_HDRLEN;
+ ip_handle(ip, pend, len);
+ break;
+#if defined(__OpenBSD__)
+ case AF_LINK:
+#else
+ case AF_LOCAL:
+#endif
+ ep = (struct ether_header *)(p + NULL_HDRLEN);
+ ether_type = ntohs(ep->ether_type);
+ if (ether_type <= ETHERMTU)
+ log_tmp("llc packet !");
+ else {
+ switch (ether_type) {
+ case ETHERTYPE_IP:
+ log_tmp("loop family AF_LINK IP");
+ ip = (struct ip *)((u_char *)ep + sizeof(*ep));
+ len -= NULL_HDRLEN + sizeof(*ep);
+ ip_handle(ip, pend, len);
+ break;
+ default:
+ log_tmp("loop non ip packet !");
+ break;
+ }
+ }
+ default:
+ log_tmp("unknown family %x !", family);
+ break;
+ }
+}
+