246 lines
5.5 KiB
C
246 lines
5.5 KiB
C
/* 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 <unistd.h>
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
#include <netinet/in.h>
|
|
#include <linux/if_ether.h>
|
|
#include <strings.h>
|
|
#include <sys/ioctl.h>
|
|
#include <linux/if.h>
|
|
#include <signal.h>
|
|
#include <linux/ip.h>
|
|
#include <linux/tcp.h>
|
|
#include <netinet/protocols.h>
|
|
#include <stdio.h>
|
|
#include <time.h>
|
|
#include <signal.h>
|
|
#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;
|
|
}
|
|
}
|