/* snooper.c * * Copyright (c) 2000 Sean Walton and Macmillan Publishers. Use may be in * whole or in part in accordance to the General Public License (GPL). * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /*****************************************************************************/ /*** snooper.c ***/ /*** ***/ /*** This program captures *all* packets that the network interface sees. ***/ /*** Be very careful with this tool, because you may see all lot of info. ***/ /*** Also, it uses the deprecated SOCK_PACKET socket type. The newer and ***/ /*** preferred method is with PF_PACKET. ***/ /*****************************************************************************/ #include #include #include #include #include #include #include #define IP_SIZE 4 #define ETH_SIZE 6 typedef enum { eETH_ADDR, eIP_ADDR } EAddress; typedef unsigned char uchar; /*--------------------------------------------------------------------*/ /* Ethernet Frame */ /* */ /* This structure defines the fields within the ethernet frame. Since */ /* this programs gets the lowest-level packet, fragmented packets are */ /* not reassembled. The first few fields contain the MAC addresses */ /* of the source and destination. Note that this structure is set for */ /* little-endian format. */ /*--------------------------------------------------------------------*/ struct ip_packet { struct { uchar dst_eth[ETH_SIZE]; uchar src_eth[ETH_SIZE]; uchar __unknwn[2]; } hw_header; /* hardware header */ uint header_len:4; /* header length in words in 32bit words */ uint version:4; /* 4-bit version */ uint serve_type:8; /* how to service packet */ uint packet_len:16; /* total size of packet in bytes */ uint ID:16; /* fragment ID */ uint frag_offset:13; /* to help reassembly */ uint more_frags:1; /* flag for "more frags to follow" */ uint dont_frag:1; /* flag to permit fragmentation */ uint __reserved:1; /* always zero */ uint time_to_live:8; /* maximum router hop count */ uint protocol:8; /* ICMP, UDP, TCP */ uint hdr_chksum:16; /* ones-comp. checksum of header */ uchar IPv4_src[IP_SIZE]; /* IP address of originator */ uchar IPv4_dst[IP_SIZE]; /* IP address of destination */ uchar options[0]; /* up to 40 bytes */ uchar data[0]; /* message data up to 64KB */ }; /*--------------------------------------------------------------------*/ /* dump */ /* */ /* Dump a block of data in hex & ascii. */ /*--------------------------------------------------------------------*/ void dump(void* b, int len) { unsigned char *buf = b; int i, cnt=0; char str[17]; memset(str, 0, 17); for ( i = 0; i < len; i++ ) { if ( cnt % 16 == 0 ) { printf(" %s\nX: ", str, cnt); memset(str, 0, 17); } if ( buf[cnt] < ' ' || buf[cnt] >= 127 ) str[cnt] = '.'; else str[cnt] = buf[cnt]; printf("X ", buf[cnt++]); } printf(" %*s\n\n", 16+(16-len)*2, str); } /*--------------------------------------------------------------------*/ /* PrintAddr */ /* */ /* Print the different types of address (MAC or IP). */ /*--------------------------------------------------------------------*/ void PrintAddr(char* msg, uchar *addr, EAddress is_ip) { int i; static struct { int len; char *fmt; char delim; } addr_fmt[] = {{ETH_SIZE, "%x", ':'}, {IP_SIZE, "%d", '.'}}; printf("%s", msg); for ( i = 0; i < addr_fmt[is_ip].len; i++ ) { printf(addr_fmt[is_ip].fmt, addr[i]); if ( i < addr_fmt[is_ip].len-1 ) putchar(addr_fmt[is_ip].delim); } } /*--------------------------------------------------------------------*/ /* GetProtocol */ /* */ /* Convert the protocol value into the alphabetic representation. */ /*--------------------------------------------------------------------*/ char* GetProtocol(int value) { switch (value) { case IPPROTO_IP: return "IP"; case IPPROTO_ICMP: return "ICMP"; case IPPROTO_IGMP: return "IGMP"; case IPPROTO_IPIP: return "IPIP"; case IPPROTO_TCP: return "TCP"; case IPPROTO_EGP: return "EGP"; case IPPROTO_PUP: return "PUP"; case IPPROTO_UDP: return "UDP"; case IPPROTO_IDP: return "IDP"; case IPPROTO_RSVP: return "RSVP"; case IPPROTO_GRE: return "GRE"; case IPPROTO_IPV6: return "IPV6/4"; case IPPROTO_PIM: return "PIM"; case IPPROTO_RAW: return "RAW"; default: return "???"; } } /*--------------------------------------------------------------------*/ /* DumpPacket */ /* */ /* Display the read packet with data and fields. */ /*--------------------------------------------------------------------*/ void DumpPacket(char *buffer, int len) { struct ip_packet *ip=(void*)buffer; printf("-------------------------------------------------\n"); dump(buffer, len); PrintAddr("Destination EtherID=", ip->hw_header.dst_eth, eETH_ADDR); PrintAddr(", Source EtherID=", ip->hw_header.src_eth, eETH_ADDR); printf("\nIPv%d: header-len=%d, type=%d, packet-size=%d, ID=%d\n", ip->version, ip->header_len*4, ip->serve_type, ntohs(ip->packet_len), ntohs(ip->ID)); printf("frag=%c, more=%c, offset=%d, TTL=%d, protocol=%s\n", (ip->dont_frag? 'N': 'Y'), (ip->more_frags? 'N': 'Y'), ip->frag_offset, ip->time_to_live, GetProtocol(ip->protocol)); printf("checksum=%d, ", ntohs(ip->hdr_chksum)); PrintAddr("source=", ip->IPv4_src, eIP_ADDR); PrintAddr(", destination=", ip->IPv4_dst, eIP_ADDR); printf("\n"); fflush(stdout); } void PANIC(char *msg); #define PANIC(msg) {perror(msg);exit(0);} /*--------------------------------------------------------------------*/ /* main */ /* */ /* Open socket. Repeatedly read and display records. */ /*--------------------------------------------------------------------*/ int main() { int sd, bytes_read; char data[1024]; sd = socket(PF_INET, SOCK_PACKET, htons(ETH_P_ALL)); if ( sd < 0 ) PANIC("Snooper socket"); do { bytes_read = recvfrom(sd, data, sizeof(data), 0, 0, 0); if ( bytes_read > 0 ) DumpPacket(data, bytes_read); } while ( bytes_read > 0 ); return 0; }