/* ipxdump.c Copyright 1996 Volker Lendecke, Goettingen, Germany Copyright 1999, 2001 Petr Vandrovec, Prague, Czech Republic 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. Revision History: 1.01 1999, December, 15 Petr Vandrovec Use sigaction instead of signal, so ^C works immediately and not after next frame comes (bsd vs. sysv signal() semantic bug) 1.02 2001, July 15 Petr Vandrovec Add #include to fix some warnings. */ #include "config.h" #include #include #include /* TBD */ #include #ifdef HAVE_NETINET_IF_ETHER_H #include #else #include #endif #include #include #include #include #include /* TBD */ #include /* TBD */ #include #include #include #include #include "ipxutil.h" #include "nls.h" struct ipx_address { IPXNet net; IPXNode node; IPXPort sock; } __attribute__((packed)); 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; struct ipx_address ipx_source; } __attribute__((packed)); void handle_frame(unsigned char *buf, int length, struct sockaddr *saddr); void handle_ipx(const char *frame, unsigned char *buf); static int filter = 0; static int allframes = 0; static IPXNode filter_node; static const char* progname; static void usage(void) { fprintf(stderr, "usage: %s [-r] [-d device] [node]\n", progname); } static int exit_request = 0; static void int_handler(int dummy) { exit_request = 1; (void)dummy; } int main(int argc, char *argv[]) { int sd; struct ifreq ifr, oldifr; const char *device = "eth0"; struct sockaddr saddr; socklen_t sizeaddr; unsigned char buf[4096]; int length; int opt; struct sigaction saint; progname = strrchr(argv[0], '/'); if (progname) progname++; else progname = argv[0]; saint.sa_handler = int_handler; saint.sa_flags = 0; sigemptyset(&saint.sa_mask); sigaction(SIGINT, &saint, NULL); while ((opt = getopt(argc, argv, "rd:h")) != -1) { switch (opt) { case 'r':allframes = 1; break; case 'd':device = optarg; break; case 'h':usage(); return 5; case ':':; case '?':break; default: printf("?? unknown option returned by getopt\n"); break; } } if (optind < argc) { if (ipx_sscanf_node(argv[optind], filter_node) != 0) { usage(); exit(1); } filter = 1; } setvbuf(stdout, NULL, _IOLBF, 0); // if ((sd = socket(AF_INET, SOCK_PACKET, htons(ETH_P_ALL))) < 0) if ((sd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) < 0) { perror("Can't get socket"); fprintf(stderr, "You must run %s as root\n", progname); 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; if (allframes) { unsigned char* ptr = buf; if (filter) { if (memcmp(filter_node, buf, 6)&&memcmp(filter_node, buf+6, 6)) continue; } printf("raweth "); while (length--) printf("%02X", *ptr++); printf("\n"); } else { 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); return 0; } void handle_ipx(const 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) { (void)length; (void)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 (htons(packet_type)) { case ETH_P_IPX: handle_ipx("EtherII", &(buf[sizeof(struct ethhdr)])); break; default: handle_other(buf, length, saddr); break; } }