/* ipxdump.c */ /* Copyright 1996 Volker Lendecke, Goettingen, Germany * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ipxutil.h" struct ipx_address { unsigned long net; unsigned char node[IPX_NODE_LEN]; unsigned short sock; }; struct ipx_packet { unsigned short ipx_checksum; #define IPX_NO_CHECKSUM 0xFFFF unsigned short ipx_pktsize; unsigned char ipx_tctrl; unsigned char ipx_type; #define IPX_TYPE_UNKNOWN 0x00 #define IPX_TYPE_RIP 0x01 /* may also be 0 */ #define IPX_TYPE_SAP 0x04 /* may also be 0 */ #define IPX_TYPE_SPX 0x05 /* Not yet implemented */ #define IPX_TYPE_NCP 0x11 /* $lots for docs on this (SPIT) */ #define IPX_TYPE_PPROP 0x14 /* complicated flood fill brdcast [Not supported] */ struct ipx_address ipx_dest __attribute__ ((packed)); struct ipx_address ipx_source __attribute__ ((packed)); }; void handle_frame (unsigned char *buf, int length, struct sockaddr *saddr); void handle_ipx(char *frame, unsigned char *buf); static int filter = 0; static IPXNode filter_node; static int exit_request = 0; static void int_handler() { exit_request = 1; } void main (int argc, char *argv[]) { int sd; struct ifreq ifr, oldifr; char *device = "eth0"; struct sockaddr saddr; int sizeaddr; unsigned char buf[4096]; int length; signal(SIGINT, int_handler); if (argc > 1) { if (ipx_sscanf_node(argv[1], filter_node) != 0) { fprintf(stderr, "usage: %s [node]\n", argv[0]); exit(1); } filter = 1; } if ((sd = socket (AF_INET, SOCK_PACKET, htons (ETH_P_ALL))) < 0) { perror ("Can't get socket"); fprintf(stderr, "You must run %s as root\n", argv[0]); exit (1); } /* SET PROMISC */ strcpy (oldifr.ifr_name, device); if (ioctl (sd, SIOCGIFFLAGS, &oldifr) < 0) { close (sd); perror ("Can't get flags"); exit (2); } /* This should be rewritten to cooperate with other net tools */ ifr = oldifr; ifr.ifr_flags |= IFF_PROMISC; if (ioctl (sd, SIOCSIFFLAGS, &ifr) < 0) { close (sd); perror ("Can't set flags"); exit (3); } while ( exit_request == 0 ) { /* This is the main data-gathering loop; keep it small and fast */ sizeaddr = sizeof(saddr); length = recvfrom (sd, buf, sizeof(buf), 0, &saddr, &sizeaddr); if (length < 0 ) continue; handle_frame (buf, length, &saddr); } /* This should be rewritten to cooperate with other net tools */ if (ioctl (sd, SIOCSIFFLAGS, &oldifr) < 0) { close (sd); perror ("Can't set flags"); exit (4); } close (sd); exit (0); } void handle_ipx (char *frame, unsigned char *buf) { int i; struct ipx_packet *h = (struct ipx_packet *)buf; struct sockaddr_ipx s_addr; struct sockaddr_ipx d_addr; int length = ntohs(h->ipx_pktsize); memset(&s_addr, 0, sizeof(s_addr)); memset(&d_addr, 0, sizeof(d_addr)); memcpy(s_addr.sipx_node, h->ipx_source.node, sizeof(s_addr.sipx_node)); s_addr.sipx_port = h->ipx_source.sock; s_addr.sipx_network = h->ipx_source.net; memcpy(d_addr.sipx_node, h->ipx_dest.node, sizeof(d_addr.sipx_node)); d_addr.sipx_port = h->ipx_dest.sock; d_addr.sipx_network = h->ipx_dest.net; if (filter != 0) { if ( (memcmp(filter_node, s_addr.sipx_node, sizeof(filter_node)) != 0) && (memcmp(filter_node, d_addr.sipx_node, sizeof(filter_node)) != 0)) { /* Not for us */ return; } } printf("%s ", frame); for (i = 0; i < length; i++) { printf("%2.2X", buf[i]); } printf("\n"); if (!isatty(STDOUT_FILENO)) { fflush(stdout); } } void handle_other (unsigned char *buf, int length, struct sockaddr *saddr) { struct ethhdr *eth = (struct ethhdr *)buf; unsigned char *p = &(buf[sizeof(struct ethhdr)]); if (ntohs(eth->h_proto) < 1536) { /* This is a magic hack to spot IPX packets. Older * Novell breaks the protocol design and runs IPX over * 802.3 without an 802.2 LLC layer. We look for FFFF * which isnt a used 802.2 SSAP/DSAP. This won't work * for fault tolerant netware but does for the rest. */ if (*(unsigned short *)p == 0xffff) { handle_ipx("802.3", p); return; } if ( (*(unsigned short *)p == htons(0xe0e0)) && (p[2] == 0x03)) { handle_ipx("802.2", p+3); return; } if (memcmp(p, "\252\252\003\000\000\000\201\067", 8) == 0) { handle_ipx("snap", p+8); return; } } } void handle_frame (unsigned char *buf, int length, struct sockaddr *saddr) { /* Ethernet packet type ID field */ unsigned short packet_type = ((struct ethhdr *)buf)->h_proto; switch( packet_type ) { case __constant_ntohs(ETH_P_IPX): handle_ipx("EtherII", &(buf[sizeof(struct ethhdr)])); break; default: handle_other(buf, length, saddr); break; } }