/* * Linux-sniff v1.0 * * Copyright (C) 2000 Xphere (Xphere@bofh.obit.nl). * * Linux eth/tcp/ip sniffer. This tool logs printable data * in the packet or it gives detailed info about the eth/tcp/ip * packet headers. For educational use only. E-mail comments * and whatever you want to Xphere (Xphere@bofh.obit.nl). * * Compile: gcc linux-sniff.c -o linux-sniff * * Greetz: #phreak.nl - http://www.casema.net/~gin * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include struct packet_id { unsigned long src_addr; unsigned long dst_addr; unsigned short src_port; unsigned short dst_port; int state; int d_size; long start_time; char *data; } pkt_list[1000]; int open_fd(char *intf) { int f, s; struct ifreq ifr; if ((f = socket(AF_INET, SOCK_PACKET, htons(0x800))) < 0) { return(-1); } strcpy(ifr.ifr_name, intf); if ((s = ioctl(f, SIOCGIFFLAGS, &ifr)) < 0) { close(f); return(-1); } ifr.ifr_flags |= IFF_PROMISC; if ((s = ioctl(f, SIOCSIFFLAGS, &ifr)) < 0) { return(-1); } return(f); } char *lookup(long ip) { static char n[1024]; struct in_addr ia; struct hostent *he; ia.s_addr = ip; he = gethostbyaddr((char *) &ia, sizeof(struct in_addr), AF_INET); if ((sizeof(he->h_name) <= sizeof(n)) && he != NULL) { strcpy(n, he->h_name); } else { strcpy(n, inet_ntoa(ia)); } return(n); } void print_ethhdr(struct ethhdr *eth) { fprintf(stdout, "+-----< Ethernet Header >\n|\n"); fprintf(stdout, "| Ethernet Destination (h_dest):\t%u\n", eth->h_dest); fprintf(stdout, "| Ethernet Source (h_source):\t\t%u\n", eth->h_source); fprintf(stdout, "| Ethernet Protocol (h_proto):\t\t%u\n|\n", eth->h_proto); return; } void print_iphdr(struct iphdr *ip) { fprintf(stdout, "+-----< IP Header >\n|\n"); fprintf(stdout, "| Version (version):\t\t\t%d\n", ntohs(ip->version)); fprintf(stdout, "| IHL (ihl):\t\t\t\t%d\n", ntohs(ip->ihl)); fprintf(stdout, "| Type of Service (tos):\t\t%d\n", ntohs(ip->tos)); fprintf(stdout, "| Total Length (tot_len):\t\t%d\n", ntohs(ip->tot_len)); fprintf(stdout, "| Identification (id):\t\t\t%d\n", ntohs(ip->id)); fprintf(stdout, "| Fragment Offset (frag_off):\t\t%u\n", ip->frag_off); fprintf(stdout, "| Time to Live (ttl):\t\t\t%d\n", ntohs(ip->ttl)); fprintf(stdout, "| Protocol (protocol):\t\t\t%d\n", ntohs(ip->protocol)); fprintf(stdout, "| Header Checksum (check):\t\t%d\n", ntohs(ip->check)); fprintf(stdout, "| Source Address (saddr):\t\t%u\n", ip->saddr); fprintf(stdout, "| Destination Address (daddr):\t\t%u\n|\n", ip->daddr); return; } void print_tcphdr(struct tcphdr *tcp) { fprintf(stdout, "+-----< TCP HEADER >\n|\n"); fprintf(stdout, "| Source Port (source):\t\t\t%d\n", tcp->source); fprintf(stdout, "| Destination Port (dest):\t\t%d\n", tcp->dest); fprintf(stdout, "| Sequence Number (seq):\t\t%x\n", tcp->seq); fprintf(stdout, "| Acknowledgment Number (ack):\t\t%x\n", tcp->ack_seq); fprintf(stdout, "| Data Offset (doff):\t\t\t%d\n", ntohs(tcp->doff)); fprintf(stdout, "| Reserverd 1 (res1):\t\t\t%d\n", ntohs(tcp->res1)); fprintf(stdout, "| Reserverd 2 (res2):\t\t\t%d\n", ntohs(tcp->res2)); fprintf(stdout, "| Flags (urg|ack|psh|rst|syn|fin):\t"); if (tcp->urg == 1) { fprintf(stdout, "URG "); } if (tcp->ack == 1) { fprintf(stdout, "ACK "); } if (tcp->psh == 1) { fprintf(stdout, "PSH "); } if (tcp->rst == 1) { fprintf(stdout, "RST "); } if (tcp->syn == 1) { fprintf(stdout, "SYN "); } if (tcp->fin == 1) { fprintf(stdout, "FIN "); } fprintf(stdout, "\n| Window (window):\t\t\t%d\n", ntohs(tcp->window)); fprintf(stdout, "| Header Checksum (check):\t\t%d\n", ntohs(tcp->check)); fprintf(stdout, "| Urgent Pointer (urg_ptr):\t\t%u\n", tcp->urg_ptr); return; } void print_dat(int d_size, char *data) { int i = 0; for (i = 0; i < d_size; ++i) { if(data[i] == 13) { fprintf(stdout, "\n"); } if(isprint(data[i])) { fprintf(stdout, "%c", data[i]); } } return; } void print_pkt(unsigned long saddr, unsigned long daddr, unsigned short src_port, unsigned short dst_port, int d_size, char *data) { fprintf(stdout, "+-----< HOST: %s ", lookup(saddr)); fprintf(stdout, "PORT: %d -> ", ntohs(src_port)); fprintf(stdout, "HOST: %s ", lookup(daddr)); fprintf(stdout, "PORT: %d >\n\n", ntohs(dst_port)); print_dat(d_size, data); return; } void rm_pkt(int i) { pkt_list[i].src_addr = 0; pkt_list[i].dst_addr = 0; pkt_list[i].src_port = 0; pkt_list[i].dst_port = 0; pkt_list[i].state = 0; pkt_list[i].d_size = 0; pkt_list[i].start_time = 0; free(pkt_list[i].data); pkt_list[i].data = NULL; return; } void check_pkt() { int i; for (i = 0; i < 1000; ++i) { if (pkt_list[i].state == 1) { if ((pkt_list[i].start_time + 1000) < time(NULL)) { print_pkt(pkt_list[i].src_addr, pkt_list[i].dst_addr, pkt_list[i].src_port, pkt_list[i].dst_port, pkt_list[i].d_size, pkt_list[i].data); fprintf(stdout, "\n+-----< Timed out. >\n\n\n"); rm_pkt(i); } } } return; } int find_pkt(struct iphdr *ip, struct tcphdr *tcp) { int i; for (i = 0; i < 1000; ++i) { if (pkt_list[i].state == 1) { if ((pkt_list[i].src_addr == ip->saddr) && (pkt_list[i].dst_addr == ip->daddr) && (pkt_list[i].src_port == tcp->source) && (pkt_list[i].dst_port == tcp->dest)) { return(i); } } } return(-1); } void reset_pkt(struct iphdr *ip, struct tcphdr *tcp) { int i; if ((i = find_pkt(ip, tcp)) > -1) { print_pkt(pkt_list[i].src_addr, pkt_list[i].dst_addr, pkt_list[i].src_port, pkt_list[i].dst_port, pkt_list[i].d_size, pkt_list[i].data); fprintf(stdout, "\n+-----< Received FIN/RST. >\n\n\n"); rm_pkt(i); } return; } void init_pkt(struct iphdr *ip, struct tcphdr *tcp) { int i; for (i = 0; i < 1000; ++i) { if (pkt_list[i].state == 0) { pkt_list[i].src_addr = ip->saddr; pkt_list[i].dst_addr = ip->daddr; pkt_list[i].src_port = tcp->source; pkt_list[i].dst_port = tcp->dest; pkt_list[i].state = 1; pkt_list[i].start_time = time(NULL); return; } } return; } void data_pkt(struct iphdr *ip, struct tcphdr *tcp, int d_size, char *data) { int i, t, k = 0; char *bsd; if ((i = find_pkt(ip, tcp)) > -1) { if (d_size > 0) { if (pkt_list[i].data == NULL) { pkt_list[i].data = malloc(d_size); pkt_list[i].d_size += d_size; for (t = 0; t < d_size; ++t) { pkt_list[i].data[t] = data[t]; } } else { bsd = pkt_list[i].data; pkt_list[i].data = malloc(pkt_list[i].d_size + d_size); for (t = 0; t < pkt_list[i].d_size; ++t) { pkt_list[i].data[k] = bsd[t]; ++k; } pkt_list[i].d_size += d_size; for (t = 0; t < d_size; ++t) { pkt_list[i].data[k] = data[t]; ++k; } free(bsd); } } } return; } void proc_packet(char *buf, int mode) { struct ethhdr *eth; struct iphdr *ip; struct tcphdr *tcp; char *data; int d_size, e_size, i_size, t_size; e_size = sizeof(struct ethhdr); i_size = sizeof(struct iphdr); t_size = sizeof(struct tcphdr); eth = (struct ethhdr *) buf; ip = (struct iphdr *) (buf + e_size); tcp = (struct tcphdr *) (buf + e_size + i_size); data = (buf + e_size + i_size + t_size); d_size = (htons(ip->tot_len) - i_size - t_size); if (ip->protocol != 6) { return; } if (mode == 1) { check_pkt(); if ((tcp->syn == 1) && (find_pkt(ip, tcp) == -1)) { init_pkt(ip, tcp); } else if ((tcp->rst == 1) || (tcp->fin == 1)) { reset_pkt(ip, tcp); } else { data_pkt(ip, tcp, d_size, data); } /* print_dat(d_size, data); fflush(stdout); */ } else if (mode == 2) { fprintf(stdout, "+-----< HOST: %s ", lookup(ip->saddr)); fprintf(stdout, "PORT: %d -> ", tcp->source); fprintf(stdout, "HOST: %s ", lookup(ip->daddr)); fprintf(stdout, "PORT: %d >\n", ntohs(tcp->dest)); fprintf(stdout, "| SEQ:\t\t%x\n", tcp->seq); fprintf(stdout, "| ACK:\t\t%x\n", tcp->ack_seq); fprintf(stdout, "| FLAGS:\t"); if (tcp->urg == 1) { fprintf(stdout, "URG "); } if (tcp->ack == 1) { fprintf(stdout, "ACK "); } if (tcp->psh == 1) { fprintf(stdout, "PSH "); } if (tcp->rst == 1) { fprintf(stdout, "RST "); } if (tcp->syn == 1) { fprintf(stdout, "SYN "); } if (tcp->fin == 1) { fprintf(stdout, "FIN "); } fprintf(stdout, "\n\n\n"); fflush(stdout); } else if (mode == 3) { fprintf(stdout, "+-----< HOST: %s ", lookup(ip->saddr)); fprintf(stdout, "PORT: %d -> ", tcp->source); fprintf(stdout, "HOST: %s ", lookup(ip->daddr)); fprintf(stdout, "PORT: %d >\n", ntohs(tcp->dest)); print_ethhdr(eth); print_iphdr(ip); print_tcphdr(tcp); fprintf(stdout, "\n\n\n"); fflush(stdout); } return; } void init_pkt_list() { int i; for (i = 0; i < 1000; ++i) { pkt_list[i].src_addr = 0; pkt_list[i].dst_addr = 0; pkt_list[i].src_port = 0; pkt_list[i].dst_port = 0; pkt_list[i].state = 0; pkt_list[i].start_time = 0; pkt_list[i].data = NULL; } return; } void terminate() { fprintf(stdout, "Received signal, exiting.\n"); exit(0); } int main (int argc, char *argv[]) { int sd, i, mode; char buf[1500]; if (argc != 3) { fprintf(stderr, "\n\e[0;34m[ Linux-sniff v1.0 "); fprintf(stderr, "by: Xphere -- #phreak.nl ]\e[0m\n\n\n"); fprintf(stderr, "Usage: %s \n\n", argv[0]); fprintf(stderr, " - mode 1: data sniff mode.\n"); fprintf(stderr, " - mode 2: tcp/ip packet info mode.\n"); fprintf(stderr, " - mode 3: verbose packet info mode.\n"); fprintf(stderr, "\nExample: %s eth0 1 > sniff.log &\n", argv[0]); exit(-1); } if ((mode = atoi(argv[2])) < 1) { fprintf(stderr, "Error: argument 2 must be 1, 2 or 3\n"); exit(-1); } if ((sd = open_fd(argv[1])) < 0) { fprintf(stderr, "Error: can't get promicuous socket.\n"); exit(-1); } signal(SIGINT, terminate); signal(SIGKILL, terminate); signal(SIGQUIT, terminate); signal(SIGTERM, terminate); signal(SIGHUP, SIG_IGN); fprintf(stdout, "\n[ Linux-sniff "); fprintf(stdout, "by: Xphere -- #phreak.nl ]\n\n\n"); if (mode == 1) { init_pkt_list(); } while (1) { if ((i = read(sd, buf, 1499)) > 1) { proc_packet(buf, mode); } } exit(0); }